Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>; final String oldName; final int orderOfOccurrence; String newName; int count; // Number of times this is referenced Assignment(String name, CompilerInput input) { this.input = input; this.oldName = name; this.newName = null; this.count = 0; // Represents the order at which a symbol appears in the source. this.orderOfOccurrence = assignmentCount++; } /** * Assigns the new name. */ void setNewName(String newName) { Preconditions.checkState(this.newName == null); this.newName = newName; } } /** Maps an old name to a new name assignment */ private final SortedMap<String, Assignment> assignments = new TreeMap<String, Assignment>(); /** Whether renaming should apply to local variables only. */ private final boolean localRenamingOnly; /** * Whether anonymous function names should be preserved. Typically, for * debugging purposes. * @see NameAnonymousFunctions */ private boolean preserveAnonymousFunctionNames; /** Generate pseudo names for variables for debugging purposes */ private boolean generatePseudoNames; /** Characters that shouldn't be used in variable names. */ private final char[] reservedCharacters; /** A prefix to distinguish temporary local names from global names */ private static final String LOCAL_VAR_PREFIX = "L "; RenameVars(AbstractCompiler compiler, String prefix, boolean localRenamingOnly, boolean preserveAnonymousFunctionNames, boolean generatePseudoNames, VariableMap prevUsedRenameMap, @Nullable char[] reservedCharacters, @Nullable Set<String> reservedNames) { this.compiler = compiler; this.prefix = prefix == null ? "" : prefix; this.localRenamingOnly = localRenamingOnly; this.preserveAnonymousFunctionNames = preserveAnonymousFunctionNames; this.generatePseudoNames = generatePseudoNames; this.prevUsedRenameMap = prevUsedRenameMap; this.reservedCharacters = reservedCharacters; if (reservedNames == null) { this.reservedNames = Sets.newHashSet(); } else { this.reservedNames = Sets.newHashSet(reservedNames); } } /** * Iterate through the nodes, collect all the NAME nodes that need to be * renamed, and count how many times

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> each variable name is referenced. * * There are 2 passes: * - externs: keep track of the global vars in the externNames_ map. * - source: keep track of all name references in globalNameNodes_, and * localNameNodes_. * * To get shorter local variable renaming, we rename local variables to a * temporary name "LOCAL_VAR_PREFIX + index" where index is the index of the * variable declared in the local scope stack. * e.g. * Foo(fa, fb) { * var c = function(d, e) { return fa; } * } * The indexes are: fa:0, fb:1, c:2, d:3, e:4 * * In that way, local variable names are reused in each global function. * e.g. the final code might look like * function x(a,b) { ... } * function y(a,b,c) { ... } */ class ProcessVars extends AbstractPostOrderCallback { private final boolean isExternsPass_; ProcessVars(boolean isExterns) { isExternsPass_ = isExterns; } @Override public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() != Token.NAME) { return; } String name = n.getString(); // Ignore anonymous functions if (name.length() == 0) { return; incCount(tempName, null); localNameNodes.add(n); localTempNames.add(tempName); } else if (var != null) { // Not an extern // If it's global, increment global count incCount(name, var.input); globalNameNodes.add(n); } } // Increment count of an assignment void incCount(String name, CompilerInput input) { Assignment s = assignments.get(name); if (s == null) { s = new Assignment(name, input); assignments.put(name, s); } s.count++; } } /** * Sorts Assignment objects by their count, breaking ties by their * order of occurrence in the source to ensure a deterministic total

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> * ordering. */ private static final Comparator<Assignment> FREQUENCY_COMPARATOR = new Comparator<Assignment>() { public int compare(Assignment a1, Assignment a2) { if (a1.count != a2.count) { return a2.count - a1.count; } // Break a tie using the order in which the variable first appears in // the source. return ORDER_OF_OCCURRENCE_COMPARATOR.compare(a1, a2); } }; /** * Sorts Assignment objects by the order the variable name first appears in * the source. */ private static final Comparator<Assignment> ORDER_OF_OCCURRENCE_COMPARATOR = new Comparator<Assignment>() { public int compare(Assignment a1, Assignment a2) { return a1.orderOfOccurrence - a2.orderOfOccurrence; } }; /** * {@inheritDoc} */ public void process(Node externs, Node root) { assignmentLog = new StringBuilder(); // Do variable reference counting. NodeTraversal.traverse(compiler, externs, new ProcessVars(true)); NodeTraversal.traverse(compiler, root, new ProcessVars(false)); // Make sure that new names don't overlap with extern names. reservedNames.addAll(externNames); // Rename vars, sorted by frequency of occurrence to minimize code size. SortedSet<Assignment> varsByFrequency = new TreeSet<Assignment>(FREQUENCY_COMPARATOR); varsByFrequency.addAll(assignments.values()); // First try to reuse names from an earlier compilation. if (prevUsedRenameMap != null) { reusePreviouslyUsedVariableMap(); } // Assign names, sorted by descending frequency to minimize code size. assignNames(varsByFrequency); boolean changed = false; // Rename the globals! for (Node n : globalNameNodes) { String newName = getNewGlobalName(n); // Note: if newName is null, then oldName is an extern. if (newName != null) { n.setString(newName); changed = true; } } // Rename the locals! int count = 0; for (Node n : localNameNodes) { String newName = getNewLocalName

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>(n, count); if (newName != null) { n.setString(newName); changed = true; } count++; } if (changed) { compiler.reportCodeChange(); } // Lastly, write the name assignments to the debug log. compiler.addToDebugLog("JS var assignments:\n" + assignmentLog); assignmentLog = null; } private String getNewGlobalName(Node n) { String oldName = n.getString(); Assignment a = assignments.get(oldName); if (a.newName != null && !a.newName.equals(oldName)) { if (generatePseudoNames) { return getPseudoName(oldName); } return a.newName; } else { return null; } } private String getNewLocalName(Node n, int index) { String oldTempName = localTempNames.get(index); Assignment a = assignments.get(oldTempName); if (!a.newName.equals(oldTempName)) { if (generatePseudoNames) { return getPseudoName(n.getString()); } return a.newName; } return null; } private String getPseudoName(String s) { Preconditions.checkState(generatePseudoNames); // Variable names should be in a different name space than // property pseudo names. return '$' + s + "$$"; } /** * Runs through the assignments and reuses as many names as possible from the * previously used variable map. Updates reservedNames with the set of names * that were reused. */ private void reusePreviouslyUsedVariableMap() { for (Assignment a : assignments.values()) { String prevNewName = prevUsedRenameMap.lookupNewName(a.oldName); if (prevNewName == null || reservedNames.contains(prevNewName)) { continue; } if (a.oldName.startsWith(LOCAL_VAR_PREFIX) || (!externNames.contains(a.oldName) && prevNewName.startsWith(prefix))) { reservedNames.add(prevNewName); finalizeNameAssignment(a, prevNewName); } } } /** * Determines which new names to substitute for the original

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> names. */ private void assignNames(Set<Assignment> varsToRename) { NameGenerator globalNameGenerator = new NameGenerator(reservedNames, prefix, reservedCharacters); // Local variables never need a prefix. NameGenerator localNameGenerator = prefix.isEmpty() ? globalNameGenerator : new NameGenerator(reservedNames, "", reservedCharacters); // Generated names and the assignments for non-local vars. List<Assignment> pendingAssignments = new ArrayList<Assignment>(); List<String> generatedNamesForAssignments = new ArrayList<String>(); for (Assignment a : varsToRename) { if (a.newName != null) { continue; } if (externNames.contains(a.oldName)) { continue; } String newName; if (a.oldName.startsWith(LOCAL_VAR_PREFIX)) { // For local variable, we make the assignment right away. newName = localNameGenerator.generateNextName(); finalizeNameAssignment(a, newName); } else { // For non-local variable, delay finalizing the name assignment // until we know how many new names we'll have of length 2, 3, etc. newName = globalNameGenerator.generateNextName(); pendingAssignments.add(a); generatedNamesForAssignments.add(newName); } reservedNames.add(newName); } // Now that we have a list of generated names, and a list of variable // Assignment objects, we assign the generated names to the vars as // follows: // 1) The most frequent vars get the shorter names. // 2) If N number of vars are going to be assigned names of the same // length, we assign the N names based on the order at which the vars // first appear in the source. This makes the output somewhat less // random, because symbols declared close together are assigned names // that are quite similar. With this heuristic, the output is more // compressible. // For instance, the output may look like: // var da = "..", ea = ".."; // function fa() { .. } function ga() { .. } int numPendingAssignments = generatedNamesForAssignments.size(); for (int i = 0; i < numPendingAssignments;) { SortedSet

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS><Assignment> varsByOrderOfOccurrence = new TreeSet<Assignment>(ORDER_OF_OCCURRENCE_COMPARATOR); // Add k number of Assignment to the set, where k is the number of // generated names of the same length. int len = generatedNamesForAssignments.get(i).length(); for (int j = i; j < numPendingAssignments && generatedNamesForAssignments.get(j).length() == len; j++) { varsByOrderOfOccurrence.add(pendingAssignments.get(j)); } // Now, make the assignments for (Assignment a : varsByOrderOfOccurrence) { finalizeNameAssignment(a, generatedNamesForAssignments.get(i)); ++i; } } } /** * Makes a final name assignment. */ private void finalizeNameAssignment(Assignment a, String newName) { a.setNewName(newName); // Keep track of the mapping renameMap.put(a.oldName, newName); // Log the mapping assignmentLog.append(a.oldName).append(" => ").append(newName). append('\n'); } /** * Gets the variable map. */ VariableMap getVariableMap() { return new VariableMap(renameMap); } /** * Determines whether a variable name is okay to rename. */ private boolean okToRenameVar(String name, boolean isLocal) { return !compiler.getCodingConvention().isExported(name, isLocal); } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>compiler = compiler; } public void process(Node externs, Node root) { externMethods.clear(); externMethodsWithoutSignatures.clear(); getSignatureStore().reset(); methodDefinitions.clear(); if (externs != null) { NodeTraversal.traverse(compiler, externs, new GetExternMethods()); } List<Node> externsAndJs = Lists.newArrayList(externs, root); NodeTraversal.traverseRoots( compiler, Lists.newArrayList(externs, root), new GatherSignatures()); * do not have a signature are flagged to be ignored when doing arity checks. * Methods that do include signatures will be checked. */ private class GetExternMethods extends AbstractPostOrderCallback { public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.GETPROP: case Token.GETELEM: { Node dest = n.getFirstChild().getNext(); if (dest.getType() != Token.STRING) { return; } String name = dest.getString(); // We have a signature. Parse tree of the form: // assign <- parent // getprop <- n // name methods // string setTimeout // function if (parent.getType() == Token.ASSIGN && parent.getFirstChild() == n && n.getNext().getType() == Token.FUNCTION) { addSignature(name, n.getNext(), t.getSourceName()); } else { getSignatureStore().removeSignature(name); externMethodsWithoutSignatures.add(name); } externMethods.add(name); } break; case Token.OBJECTLIT: { // assumes the object literal is well formed // (has an even number of children) for (Node key = n.getFirstChild(); key != null; key = key.getNext().getNext()) { if (key.getType() == Token.STRING) { Node value = key.getNext(); String name = key.getString(); if (value.getType() == Token.FUNCTION) { addSignature(name, value, t.getSourceName()); } else { getSignatureStore().removeSignature(name); externMethodsWithoutSignatures.add(name); } externMethods.add(name

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>); } } } break; } } } /** * Gather signatures from the source to be compiled. */ private class GatherSignatures extends AbstractPostOrderCallback { public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.GETPROP: case Token.GETELEM: Node dest = n.getFirstChild().getNext(); if (dest.getType() == Token.STRING) { if (dest.getString().equals("prototype")) { processPrototypeParent(t, parent); } else { // Static methods of the form Foo.bar = function() {} or // Static methods of the form Foo.bar = baz (where baz is a // function name). Parse tree looks like: // assign <- parent // getprop <- n // name Foo // string bar // function or name <- n.getNext() if (parent.getType() == Token.ASSIGN && parent.getFirstChild() == n) { addPossibleSignature(dest.getString(), n.getNext(), t); } } } break; case Token.OBJECTLIT: // assumes the object literal is well formed // (has an even number of children) for (Node key = n.getFirstChild(); key != null; key = key.getNext().getNext()) { if (key.getType() == Token.STRING) { Node value = key.getNext(); addPossibleSignature(key.getString(), value, t); } } break; } } /** * Processes the parent of a GETPROP prototype, which can either be * another GETPROP (in the case of Foo.prototype.bar), or can be * an assignment (in the case of Foo.prototype = ...). */ private void processPrototypeParent(NodeTraversal t, Node n) { switch (n.getType()) { // Foo.prototype.getBar = function() { ... } or // Foo.prototype.getBar = getBaz (where getBaz is a function) // parse tree looks like: // assign <- parent // getprop <- n // getprop // name Foo // string prototype // string getBar // function

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> or name <- assignee case Token.GETPROP: case Token.GETELEM: Node dest = n.getFirstChild().getNext(); Node parent = n.getParent().getParent(); if (dest.getType() == Token.STRING && parent.getType() == Token.ASSIGN) { Node assignee = parent.getFirstChild().getNext(); addPossibleSignature(dest.getString(), assignee, t); } break; } } } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> X="continue";id=Id_continue; break L; case 'd': X="debugger";id=Id_debugger; break L; case 'f': X="function";id=Id_function; break L; case 'v': X="volatile";id=Id_volatile; break L; } break L; case 9: c=s.charAt(0); if (c=='i') { X="interface";id=Id_interface; } else if (c=='p') { X="protected";id=Id_protected; } else if (c=='t') { X="transient";id=Id_transient; } break L; case 10: c=s.charAt(1); if (c=='m') { X="implements";id=Id_implements; } else if (c=='n') { X="instanceof";id=Id_instanceof; } break L; case 12: X="synchronized";id=Id_synchronized; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# // #/string_id_map# if (id == 0) { return Token.EOF; } return id & 0xff; } public static boolean isJSIdentifier(String s) { int length = s.length(); if (length == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) return false; for (int i=1; i<length; i++) { char c = s.charAt(i); if (!Character.isJavaIdentifierPart(c)) { if (c == '\\') { if (! ((i + 5) < length) && (s.charAt(i + 1) == 'u') && 0 <= Kit.xDigitToInt(s.charAt(i + 2), 0) && 0 <= Kit.xDigitToInt(s.charAt(i + 3), 0) && 0 <= Kit.xDigitToInt(s.charAt(i + 4), 0) && 0 <= Kit.xDigitToInt(s.charAt(i + 5), 0

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> getOffset() { return sourceCursor - lineStart - ungetCursor - 1; } final String getLine() { if (sourceString != null) { // String case int lineEnd = sourceCursor; if (lineEndChar >= 0) { --lineEnd; } else { for (; lineEnd != sourceEnd; ++lineEnd) { int c = sourceString.charAt(lineEnd); if (ScriptRuntime.isJSLineTerminator(c)) { break; } } } return sourceString.substring(lineStart, lineEnd); } else { // Reader case int lineLength = sourceCursor - lineStart; if (lineEndChar >= 0) { --lineLength; } else { // Read until the end of line for (;; ++lineLength) { int i = lineStart + lineLength; if (i == sourceEnd) { try { if (!fillSourceBuffer()) { break; } } catch (IOException ioe) { // ignore it, we're already displaying an error... break; } // i recalculuation as fillSourceBuffer can move saved // line buffer and change lineStart i = lineStart + lineLength; } int c = sourceBuffer[i]; if (ScriptRuntime.isJSLineTerminator(c)) { break; } } } return new String(sourceBuffer, lineStart, lineLength); } } private boolean fillSourceBuffer() throws IOException { if (sourceString != null) Kit.codeBug(); if (sourceEnd == sourceBuffer.length) { if (lineStart != 0) { System.arraycopy(sourceBuffer, lineStart, sourceBuffer, 0, sourceEnd - lineStart); sourceEnd -= lineStart; sourceCursor -= lineStart; lineStart = 0; } else { char[] tmp = new char[sourceBuffer.length * 2]; System.arraycopy(sourceBuffer, 0, tmp, 0, sourceEnd); sourceBuffer = tmp; } } int n = sourceReader.read(sourceBuffer, sourceEnd, sourceBuffer.length - sourceEnd); if (n < 0) { return false;

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> } sourceEnd += n; return true; } /** * Set the FileLevelJsDocBuilder on the TokenStream. The TokenStream passes * the builder on to the JSDocInfoParser if it exists. Otherwise this method * is a no-op. * @param fileLevelJsDocBuilder */ public void setFileLevelJsDocBuilder( Node.FileLevelJsDocBuilder fileLevelJsDocBuilder) { } // stuff other than whitespace since start of line private boolean dirtyLine; String regExpFlags; private int pushbackToken; private int tokenno; // Set this to an inital non-null value so that the Parser has // something to retrieve even if an error has occured and no // string is found. Fosters one class of error, but saves lots of // code. private String string = ""; private double number; private char[] stringBuffer = new char[128]; private int stringBufferTop; private ObjToIntMap allStrings = new ObjToIntMap(50); // Room to backtrace from to < on failed match of the last - in <!-- private final int[] ungetBuffer = new int[3]; private int ungetCursor; private boolean hitEOF = false; private int lineStart = 0; private int lineno; private int charno = -1; private int lineEndChar = -1; private String sourceString; private Reader sourceReader; private char[] sourceBuffer; private int sourceEnd; private int sourceCursor; // for xml tokenizer private boolean xmlIsAttribute; private boolean xmlIsTagContent; private int xmlOpenTagsCount; private Parser parser; }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Line(int lineNumber) { String js = ""; try { // NOTE(nicksantos): Right now, this is optimized for few warnings. // This is probably the right trade-off, but will be slow if there // are lots of warnings in one file. js = getCode(); } catch (IOException e) { return null; } int pos = 0; int startLine = 1; // If we've saved a previous offset and it's for a line less than the // one we're searching for, then start at that point. if (lineNumber >= lastLine) { pos = lastOffset; startLine = lastLine; } for (int n = startLine; n < lineNumber; n++) { int nextpos = js.indexOf('\n', pos); if (nextpos == -1) { return null; } pos = nextpos + 1; } // Remember this offset for the next search we do. lastOffset = pos; lastLine = lineNumber; return (js.indexOf('\n', pos) == -1) ? null : js.substring(pos, js.indexOf('\n', pos)); } /** * Get a region around the indicated line number. The exact definition of a * region is implementation specific, but it must contain the line indicated * by the line number. A region must not start or end by a carriage return. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public Region getRegion(int lineNumber) { String js = ""; try { js = getCode(); } catch (IOException e) { return null; } int pos = 0; int startLine = Math.max(1, lineNumber - (SOURCE_EXCERPT_REGION_LENGTH + 1) / 2 + 1); for (int n = 1; n < startLine; n++) { int nextpos = js.indexOf('\n', pos); if (nextpos == -1) { break; } pos = nextpos + 1; }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> int end = pos; int endLine = startLine; for (int n = 0; n < SOURCE_EXCERPT_REGION_LENGTH; n++, endLine++) { end = js.indexOf('\n', end); if (end == -1) { break; } end++; } if (lineNumber >= endLine) { return null; } if (end == -1) { int last = js.length() - 1; if (js.charAt(last) == '\n') { return new SimpleRegion(startLine, endLine, js.substring(pos, last)); } else { return new SimpleRegion(startLine, endLine, js.substring(pos)); } } else { return new SimpleRegion(startLine, endLine, js.substring(pos, end)); } } public static SourceFile fromFile(String fileName, Charset c) { return fromFile(new File(fileName), c); } public static SourceFile fromFile(String fileName) { return fromFile(new File(fileName)); } public static SourceFile fromFile(File file, Charset c) { return new OnDisk(file, c); } public static SourceFile fromFile(File file) { return new OnDisk(file); } public static SourceFile fromCode(String fileName, String code) { return new Preloaded(fileName, code); } public static SourceFile fromCode(String fileName, String originalPath, String code) { return new Preloaded(fileName, originalPath, code); } public static SourceFile fromInputStream(String fileName, InputStream s) throws IOException { return fromCode(fileName, CharStreams.toString(new InputStreamReader(s, Charsets.UTF_8))); } public static SourceFile fromInputStream(String fileName, String originalPath, InputStream s) throws IOException { return fromCode(fileName, originalPath, CharStreams.toString(new InputStreamReader(s, Charsets.UTF_8))); } public static SourceFile fromReader(String fileName, Reader r) throws IOException { return fromCode(fileName, CharStreams.toString(r)); } public static SourceFile fromGenerator(String fileName, Generator generator) { return new Generated

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> right, blindScope, condition); } // right type JSType rightType = getTypeIfRefinable(right, blindScope); boolean rightIsRefineable; if (rightType != null) { rightIsRefineable = true; } else { rightIsRefineable = false; rightType = right.getJSType(); blindScope = firstPreciserScopeKnowingConditionOutcome( right, blindScope, condition); } if (condition) { rightType = (rightType == null) ? null : rightType.getRestrictedTypeGivenToBooleanOutcome(condition); // creating new scope if ((leftType != null && leftIsRefineable) || (rightType != null && rightIsRefineable)) { FlowScope informed = blindScope.createChildFlowScope(); if (leftIsRefineable && leftType != null) { declareNameInScope(informed, left, leftType); } if (rightIsRefineable && rightType != null) { declareNameInScope(informed, right, rightType); } return informed; } } return blindScope; } private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right, FlowScope blindScope, boolean condition) { FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome( left, blindScope, !condition); StaticSlot<JSType> leftVar = leftScope.findUniqueRefinedSlot(blindScope); if (leftVar == null) { return blindScope; } FlowScope rightScope = firstPreciserScopeKnowingConditionOutcome( left, blindScope, condition); rightScope = firstPreciserScopeKnowingConditionOutcome( right, rightScope, !condition); StaticSlot<JSType> rightVar = rightScope.findUniqueRefinedSlot(blindScope); if (rightVar == null || !leftVar.getName().equals(rightVar.getName())) { return blindScope; } JSType type = leftVar.getType().getLeastSupertype(rightVar.getType()); FlowScope informed = blindScope.createChildFlowScope(); informed.inferSlotType(leftVar.getName(), type); return informed;

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> } private FlowScope caseNameOrGetProp(Node name, FlowScope blindScope, boolean outcome) { JSType type = getTypeIfRefinable(name, blindScope); if (type != null) { JSType restrictedType = type.getRestrictedTypeGivenToBooleanOutcome(outcome); FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, name, restrictedType); return informed; } return blindScope; } private FlowScope caseTypeOf(Node node, JSType type, String value, boolean resultEqualsValue, FlowScope blindScope) { JSType restrictedType = getRestrictedByTypeOfResult(type, value, resultEqualsValue); if (restrictedType == null) { return blindScope; } FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, node, restrictedType); return informed; } private FlowScope caseInstanceOf(Node left, Node right, FlowScope blindScope, boolean outcome) { JSType leftType = getTypeIfRefinable(left, blindScope); if (leftType == null) { return blindScope; } JSType rightType = right.getJSType(); ObjectType targetType = typeRegistry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); if (rightType instanceof FunctionType) { targetType = (FunctionType) rightType; } Visitor<JSType> visitor; if (outcome) { visitor = new RestrictByTrueInstanceOfResultVisitor(targetType); } else { visitor = new RestrictByFalseInstanceOfResultVisitor(targetType); } JSType restrictedLeftType = leftType.visit(visitor); if (restrictedLeftType != null && !restrictedLeftType.equals(leftType)) { FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, left, restrictedLeftType); return informed; } return blindScope; } /** * Given 'property in object', ensures that the object has the property in the * informed scope by defining it as a qualified name if the object type lacks * the property and it's not in the blind scope. * @param object The node of the right-

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> code, '$' is often a namespace delimiter. To allow inlining // of namespaced constants, we strip off any namespaces here. int pos = name.lastIndexOf('$'); if (pos >= 0) { name = name.substring(pos + 1); if (name.length() == 0) { return false; } } if (!Character.isUpperCase(name.charAt(0))) { return false; } // hack way of checking that there aren't any lower-case letters return name.toUpperCase().equals(name); } /** * {@inheritDoc} * * <p>This enforces Google's convention about enum key names. They must match * the regular expression {@code [A-Z0-9][A-Z0-9_]*}. * * <p>Examples: * <ul> * <li>A</li> * <li>213</li> * <li>FOO_BAR</li> * </ul> */ @Override public boolean isValidEnumKey(String key) { return ENUM_KEY_PATTERN.matcher(key).matches(); } /** * {@inheritDoc} * * <p>In Google code, parameter names beginning with {@code opt_} are * treated as optional arguments. */ @Override public boolean isOptionalParameter(Node parameter) { return parameter.getString().startsWith(OPTIONAL_ARG_PREFIX); } @Override public boolean isVarArgsParameter(Node parameter) { return VAR_ARGS_NAME.equals(parameter.getString()); } /** * {@inheritDoc} * * <p>In Google code, any global name starting with an underscore is * considered exported. */ @Override public boolean isExported(String name, boolean local) { return !local && name.startsWith("_"); } /** * {@inheritDoc} * * <p>In Google code, private names end with an underscore, and exported * names are never considered private (see {@link #isExported}). */ @Override public boolean isPrivate(String name) { return name.endsWith("_") && !isExported(name); } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> * Covert EXPR_VOID to EXPR_RESULT to simplify the rest of the code. */ private void normalizeNodeTypes(Node n) { if (n.getType() == Token.EXPR_VOID) { n.setType(Token.EXPR_RESULT); reportChange(); } // Remove unused properties to minimize differences between ASTs // produced by the two parsers. if (n.getType() == Token.FUNCTION) { Preconditions.checkState(n.getProp(Node.FUNCTION_PROP) == null); } normalizeBlocks(n); for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { // This pass is run during the CompilerTestCase validation, so this // parent pointer check serves as a more general check. Preconditions.checkState(child.getParent() == n); normalizeNodeTypes(child); } } /** * Add blocks to IF, WHILE, DO, etc. */ private void normalizeBlocks(Node n) { if (NodeUtil.isControlStructure(n) && n.getType() != Token.LABEL && n.getType() != Token.SWITCH) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (NodeUtil.isControlStructureCodeBlock(n,c) && c.getType() != Token.BLOCK) { Node newBlock = new Node(Token.BLOCK); n.replaceChild(c, newBlock); if (c.getType() != Token.EMPTY) { newBlock.addChildrenToFront(c); } else { newBlock.setWasEmptyNode(true); } c = newBlock; reportChange(); } } } } /** * Normalize where annotations appear on the AST. Copies * around existing JSDoc annotations as well as internal annotations. */ static class PrepareAnnotations extends NodeTraversal.AbstractPostOrderCallback { private final AbstractCompiler compiler; private final CodingConvention convention; PrepareAnnotations(AbstractCompiler compiler) { this.compiler = compiler; this.convention = compiler.getCodingConvention(); } /** * * In the AST that Rhino gives us, it needs to make a distinction * between jsdoc

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> on the object literal node and jsdoc on the object literal * value. For example, * <pre> * var x = { * / JSDOC / * a: 'b', * c: / JSDOC / 'd' * }; * </pre> * * But in few narrow cases (in particular, function literals), it's * a lot easier for us if the doc is attached to the value. */ public void visit(NodeTraversal t, Node n, Node parent) { int nType = n.getType(); switch (nType) { case Token.NAME: case Token.STRING: String nString = n.getString(); if (nType == Token.NAME && n.getParent().getType() == Token.CALL && "eval".equals(nString)) { n.putBooleanProp(Node.DIRECT_EVAL, true); } if (convention.isConstant(nString)) { n.putBooleanProp(Node.IS_CONSTANT_NAME, true); } break; case Token.FUNCTION: JSDocInfo fnInfo = n.getJSDocInfo(); if (fnInfo == null) { // Look for the info on other nodes. if (parent.getType() == Token.ASSIGN) { // on ASSIGNs fnInfo = parent.getJSDocInfo(); } else if (parent.getType() == Token.NAME) { // on var NAME = function() { ... }; fnInfo = parent.getParent().getJSDocInfo(); } } // Compute which function parameters are optional and // which are var_args. Node args = n.getFirstChild().getNext(); for (Node arg = args.getFirstChild(); arg != null; arg = arg.getNext()) { String argName = arg.getString(); JSTypeExpression typeExpr = fnInfo == null ? null : fnInfo.getParameterType(argName); if (convention.isOptionalParameter(arg) || typeExpr != null && typeExpr.isOptionalArg()) { arg.putBooleanProp(Node.IS_OPTIONAL_PARAM, true); } if (convention.isVarArgsParameter(arg) || typeExpr != null && typeExpr.isVarArgs())

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> { arg.putBooleanProp(Node.IS_VAR_ARGS_PARAM, true); } } break; case Token.OBJECTLIT: if (n.getType() == Token.OBJECTLIT) { for (Node key = n.getFirstChild(); key != null; key = key.getNext().getNext()) { Node value = key.getNext(); if (key.getJSDocInfo() != null && key.getNext().getType() == Token.FUNCTION) { value.setJSDocInfo(key.getJSDocInfo()); } } } break; } // TODO(johnlenz): Determine if it is possible to simply use the javadoc // everywhere rather than use IS_DISPATCHER. /* * Translate dispatcher info into the property expected node. */ if (n.getJSDocInfo() != null && n.getJSDocInfo().isJavaDispatch()) { if (n.getType() == Token.ASSIGN) { Node fnNode = n.getLastChild(); Preconditions.checkState(fnNode.getType() == Token.FUNCTION); fnNode.putBooleanProp(Node.IS_DISPATCHER, true); } } } } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>} with type {4}"); static final DiagnosticType HIDDEN_PROPERTY_MISMATCH = DiagnosticType.warning("JSC_HIDDEN_PROPERTY_MISMATCH", "mismatch of the {0} property type and the type " + "of the property it overrides from superclass {1}\n" + "original: {2}\n" + "override: {3}"); static final DiagnosticType INTERFACE_METHOD_NOT_IMPLEMENTED = DiagnosticType.warning( "JSC_INTERFACE_METHOD_NOT_IMPLEMENTED", "property {0} on interface {1} is not implemented by type {2}"); static final DiagnosticGroup ALL_DIAGNOSTICS = new DiagnosticGroup( INVALID_CAST, TYPE_MISMATCH_WARNING, MISSING_EXTENDS_TAG_WARNING, DUP_VAR_DECLARATION, HIDDEN_PROPERTY_MISMATCH, INTERFACE_METHOD_NOT_IMPLEMENTED); TypeValidator(AbstractCompiler compiler) { this.compiler = compiler; this.typeRegistry = compiler.getTypeRegistry(); this.allValueTypes = typeRegistry.createUnionType( STRING_TYPE, NUMBER_TYPE, BOOLEAN_TYPE, NULL_TYPE, VOID_TYPE); } /** * Gets a list of type violations. * * For each violation, one element is the expected type and the other is * the type that is actually found. Order is not signficant. */ Iterable<TypeMismatch> getMismatches() { return mismatches; } // All non-private methods should have the form: // expectCondition(NodeTraversal t, Node n, ...); // If there is a mismatch, the {@code expect} method should issue // a warning and attempt to correct the mismatch, when possible. /** * Expect the type to be an object, or a type convertible to object. If the * expectation is not met, issue a warning at the provided node's source code * position. * @return True if there was no warning, false if there was a mismatch. */ boolean expectObject(NodeTraversal t, Node n, JSType type, String msg) { if (!type.matchesObjectContext()) { mismatch(t, n, msg, type, OBJECT_TYPE); return false; } return true; }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> /** * Expect the type to be an object. Unlike expectObject, a type convertible * to object is not acceptable. */ void expectActualObject(NodeTraversal t, Node n, JSType type, String msg) { if (!type.isObject()) { mismatch(t, n, msg, type, OBJECT_TYPE); } } /** * Expect the type to contain an object sometimes. If the expectation is * not met, issue a warning at the provided node's source code position. */ void expectAnyObject(NodeTraversal t, Node n, JSType type, String msg) { JSType anyObjectType = getNativeType(NO_OBJECT_TYPE); if (!anyObjectType.isSubtype(type)) { mismatch(t, n, msg, type, anyObjectType); } } /** * Expect the type to be a string, or a type convertible to string. If the * expectation is not met, issue a warning at the provided node's source code * position. */ void expectString(NodeTraversal t, Node n, JSType type, String msg) { if (!type.matchesStringContext()) { mismatch(t, n, msg, type, STRING_TYPE); } } /** * Expect the type to be a number, or a type convertible to number. If the * expectation is not met, issue a warning at the provided node's source code * position. */ void expectNumber(NodeTraversal t, Node n, JSType type, String msg) { if (!type.matchesNumberContext()) { mismatch(t, n, msg, type, NUMBER_TYPE); } } /** * Expect the type to be a valid operand to a bitwise operator. This includes * numbers, any type convertible to a number, or any other primitive type * (undefined|null|boolean|string). */ void expectBitwiseable(NodeTraversal t, Node n, JSType type, String msg) { if (!type.matchesNumberContext() && !type.isSubtype(allValueTypes)) { mismatch(t, n, msg, type, allValueTypes); } } /** * Expect the type to be a number or string, or a type convertible to a number * or string.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> If the expectation is not met, issue a warning at the provided * node's source code position. */ void expectStringOrNumber( NodeTraversal t, Node n, JSType type, String msg) { if (!type.matchesNumberContext() && !type.matchesStringContext()) { mismatch(t, n, msg, type, NUMBER_STRING); } } /** * Expect the type to be anything but the void type. If the expectation is not * met, issue a warning at the provided node's source code position. Note that * a union type that includes the void type and at least one other type meets * the expectation. * @return Whether the expectation was met. */ boolean expectNotVoid( NodeTraversal t, Node n, JSType type, String msg, JSType expectedType) { if (type.isVoidType()) { mismatch(t, n, msg, type, expectedType); return false; } return true; } /** * Expect that the type of a switch condition matches the type of its * case condition. */ void expectSwitchMatchesCase(NodeTraversal t, Node n, JSType switchType, JSType caseType) { // ECMA-262, page 68, step 3 of evaluation of CaseBlock, // but allowing extra autoboxing. // TODO(user): remove extra conditions when type annotations // in the code base have adapted to the change in the compiler. if (!switchType.canTestForShallowEqualityWith(caseType) && (caseType.autoboxesTo() == null || !caseType.autoboxesTo().isSubtype(switchType))) { mismatch(t, n.getFirstChild(), "case expression doesn't match switch", caseType, switchType); } } /** * Expect that the first type can be addressed with GETELEM syntax, * and that the second type is the right type for an index into the * first type. * * @param t The node traversal. * @param n The node to issue warnings on. * @param objType The type of the left side of the GETELEM. * @param indexType The type inside the brackets of the GETELEM. */ void expectIndexMatch(NodeTraversal t

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>, Node n, JSType objType, JSType indexType) { if (objType.isUnknownType()) { expectStringOrNumber(t, n, indexType, "property access"); } else if (objType.toObjectType() != null && objType.toObjectType().getIndexType() != null) { expectCanAssignTo(t, n, indexType, objType.toObjectType().getIndexType(), "restricted index type"); } else if (objType.isArrayType()) { expectNumber(t, n, indexType, "array access"); } else if (objType.matchesObjectContext()) { expectString(t, n, indexType, "property access"); } else { mismatch(t, n, "only arrays or objects can be accessed", objType, typeRegistry.createUnionType(ARRAY_TYPE, OBJECT_TYPE)); } } /** * Expect that the first type can be assigned to a symbol of the second * type. * * @param t The node traversal. * @param n The node to issue warnings on. * @param rightType The type on the RHS of the assign. * @param leftType The type of the symbol on the LHS of the assign. * @param owner The owner of the property being assigned to. * @param propName The name of the property being assigned to. * @return True if the types matched, false otherwise. */ boolean expectCanAssignToPropertyOf(NodeTraversal t, Node n, JSType rightType, JSType leftType, Node owner, String propName) { // The NoType check is a hack to make typedefs work ok. if (!leftType.isNoType() && !rightType.canAssignTo(leftType)) { if (bothIntrinsics(rightType, leftType)) { // We have a superior warning for this mistake, which gives you // the line numbers of both types. registerMismatch(rightType, leftType); } else { mismatch(t, n, "assignment to property " + propName + " of " + getReadableJSTypeName(owner, true), rightType, leftType); } return false; } return true; } /** * Expect that the first type can be

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> assigned to a symbol of the second * type. * * @param t The node traversal. * @param n The node to issue warnings on. * @param rightType The type on the RHS of the assign. * @param leftType The type of the symbol on the LHS of the assign. * @param msg An extra message for the mismatch warning, if necessary. * @return True if the types matched, false otherwise. */ boolean expectCanAssignTo(NodeTraversal t, Node n, JSType rightType, JSType leftType, String msg) { if (!rightType.canAssignTo(leftType)) { if (bothIntrinsics(rightType, leftType)) { // We have a superior warning for this mistake, which gives you // the line numbers of both types. registerMismatch(rightType, leftType); } else { mismatch(t, n, msg, rightType, leftType); } return false; } return true; } private boolean bothIntrinsics(JSType rightType, JSType leftType) { return (leftType.isConstructor() || leftType.isEnumType()) && (rightType.isConstructor() || rightType.isEnumType()); } /** * Expect that the type of an argument matches the type of the parameter * that it's fulfilling. * * @param t The node traversal. * @param n The node to issue warnings on. * @param argType The type of the argument. * @param paramType The type of the parameter. * @param callNode The call node, to help with the warning message. * @param ordinal The argument ordinal, to help with the warning message. */ void expectArgumentMatchesParameter(NodeTraversal t, Node n, JSType argType, JSType paramType, Node callNode, int ordinal) { if (!argType.canAssignTo(paramType)) { mismatch(t, n, String.format("actual parameter %d of %s does not match " + "formal parameter", ordinal, getReadableJSTypeName(callNode.getFirstChild(), false)), argType, paramType); } } /** * Expect that the first type can override a property of the second * type. *

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> * @param t The node traversal. * @param n The node to issue warnings on. * @param overridingType The overriding type. * @param hiddenType The type of the property being overridden. * @param propertyName The name of the property, for use in the * warning message. * @param ownerType The type of the owner of the property, for use * in the warning message. */ void expectCanOverride(NodeTraversal t, Node n, JSType overridingType, JSType hiddenType, String propertyName, JSType ownerType) { if (!overridingType.canAssignTo(hiddenType)) { registerMismatch(overridingType, hiddenType); compiler.report( JSError.make(t, n, HIDDEN_PROPERTY_MISMATCH, propertyName, ownerType.toString(), hiddenType.toString(), overridingType.toString())); } } /** * Expect that the first type is the direct superclass of the second type. * * @param t The node traversal. * @param n The node where warnings should point to. * @param superObject The expected super instance type. * @param subObject The sub instance type. */ void expectSuperType(NodeTraversal t, Node n, ObjectType superObject, ObjectType subObject) { FunctionType subCtor = subObject.getConstructor(); ObjectType declaredSuper = subObject.getImplicitPrototype().getImplicitPrototype(); if (!declaredSuper.equals(superObject)) { if (declaredSuper.equals(getNativeType(OBJECT_TYPE))) { compiler.report( JSError.make(t, n, MISSING_EXTENDS_TAG_WARNING, subObject.toString())); registerMismatch(superObject, declaredSuper); } else { mismatch(t.getSourceName(), n, "mismatch in declaration of superclass type", superObject, declaredSuper); } // Correct the super type. if (!subCtor.hasCachedValues()) { subCtor.setPrototypeBasedOn(superObject); } } } /** * Expect that the first type can be cast to the second type. The first type * should be either a subtype or supertype of the second. * * @param t The node traversal. * @param n The node where

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> warnings should point. * @param type The type being cast from. * @param castType The type being cast to. */ void expectCanCast(NodeTraversal t, Node n, JSType type, JSType castType) { castType = castType.restrictByNotNullOrUndefined(); type = type.restrictByNotNullOrUndefined(); if (!type.canAssignTo(castType) && !castType.canAssignTo(type)) { compiler.report( JSError.make(t, n, INVALID_CAST, castType.toString(), type.toString())); registerMismatch(type, castType); } } /** * Expect that the given variable has not been declared with a type. * * @param sourceName The name of the source file we're in. * @param n The node where warnings should point to. * @param parent The parent of {@code n}. * @param var The variable that we're checking. * @param variableName The name of the variable. * @param newType The type being applied to the variable. Mostly just here * for the benefit of the warning. */ void expectUndeclaredVariable(String sourceName, Node n, Node parent, Var var, String variableName, JSType newType) { boolean allowDupe = false; if (n.getType() == Token.GETPROP) { JSDocInfo info = n.getJSDocInfo(); if (info == null) { info = parent.getJSDocInfo(); } allowDupe = info != null && info.getSuppressions().contains("duplicate"); } JSType varType = var.getType(); // Only report duplicate declarations that have types. Other duplicates // will be reported by the syntactic scope creator later in the // compilation process. if (varType != null && varType != typeRegistry.getNativeType(UNKNOWN_TYPE) && newType != null && newType != typeRegistry.getNativeType(UNKNOWN_TYPE)) { // If there are two typed declarations of the same variable, that // is an error and the second declaration is ignored, except in the // case of native types. A null input type means that the declaration // was made in TypedScopeCreator#createInitial

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Scope and is a // native type. if (var.input == null) { n.setJSType(varType); if (parent.getType() == Token.VAR) { if (n.getFirstChild() != null) { n.getFirstChild().setJSType(varType); } } else { Preconditions.checkState(parent.getType() == Token.FUNCTION); parent.setJSType(varType); } } else { // Always warn about duplicates if the overridden type does not // match the original type. // // If the types match, suppress the warning iff there was a @suppress // tag, or if the original declaration was a stub. if (!(allowDupe || var.getParentNode().getType() == Token.EXPR_RESULT) || !newType.equals(varType)) { compiler.report( JSError.make(sourceName, n, DUP_VAR_DECLARATION, variableName, newType.toString(), var.getInputName(), String.valueOf(var.nameNode.getLineno()), varType.toString())); } } } } /** * Expect that all properties on interfaces that this type implements are * implemented. */ void expectAllInterfacePropertiesImplemented(FunctionType type) { ObjectType instance = type.getInstanceType(); for (ObjectType implemented : type.getAllImplementedInterfaces()) { if (implemented.getImplicitPrototype() != null) { for (String prop : implemented.getImplicitPrototype().getOwnPropertyNames()) { if (!instance.hasProperty(prop)) { Node source = type.getSource(); Preconditions.checkNotNull(source); String sourceName = (String) source.getProp(Node.SOURCENAME_PROP); sourceName = sourceName == null ? "" : sourceName; compiler.report(JSError.make(sourceName, source, INTERFACE_METHOD_NOT_IMPLEMENTED, prop, implemented.toString(), instance.toString())); registerMismatch(instance, implemented); } } } } } /** * Report a type mismatch */ private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSType required) { mismatch(t.getSourceName(), n, msg, found, required); }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSTypeNative required) { mismatch(t, n, msg, found, getNativeType(required)); } private void mismatch(String sourceName, Node n, String msg, JSType found, JSType required) { registerMismatch(found, required); compiler.report( JSError.make(sourceName, n, TYPE_MISMATCH_WARNING, formatFoundRequired(msg, found, required))); } private void registerMismatch(JSType found, JSType required) { // Don't register a mismatch for differences in null or undefined or if the // code didn't downcast. found = found.restrictByNotNullOrUndefined(); required = required.restrictByNotNullOrUndefined(); if (found.canAssignTo(required) || required.canAssignTo(found)) { return; } mismatches.add(new TypeMismatch(found, required)); if (found instanceof FunctionType && required instanceof FunctionType) { FunctionType fnTypeA = ((FunctionType) found); FunctionType fnTypeB = ((FunctionType) required); Iterator<Node> paramItA = fnTypeA.getParameters().iterator(); Iterator<Node> paramItB = fnTypeB.getParameters().iterator(); while (paramItA.hasNext() && paramItB.hasNext()) { registerIfMismatch(paramItA.next().getJSType(), paramItB.next().getJSType()); } registerIfMismatch(fnTypeA.getReturnType(), fnTypeB.getReturnType()); } } private void registerIfMismatch(JSType found, JSType required) { if (found != null && required != null && !found.canAssignTo(required)) { registerMismatch(found, required); } } /** * Formats a found/required error message. */ private String formatFoundRequired(String description, JSType found, JSType required) { return MessageFormat.format(FOUND_REQUIRED, description, found, required); } /** * Given a node, get a human-readable name for the type of that node so * that will be easy for the programmer to find the original declaration. * * For example, if SubFoo's property "

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>bar" might have the human-readable * name "Foo.prototype.bar". * * @param n The node. * @param dereference If true, the type of the node will be dereferenced * to an Object type, if possible. */ String getReadableJSTypeName(Node n, boolean dereference) { // If we're analyzing a GETPROP, the property may be inherited by the // prototype chain. So climb the prototype chain and find out where // the property was originally defined. if (n.getType() == Token.GETPROP) { ObjectType objectType = getJSType(n.getFirstChild()).dereference(); if (objectType != null) { String propName = n.getLastChild().getString(); while (objectType != null && !objectType.hasOwnProperty(propName)) { objectType = objectType.getImplicitPrototype(); } // Don't show complex function names or anonymous types. // Instead, try to get a human-readable type name. if (objectType != null && (objectType.getConstructor() != null || objectType.isFunctionPrototypeType())) { return objectType.toString() + "." + propName; } } } JSType type = getJSType(n); if (dereference) { ObjectType dereferenced = type.dereference(); if (dereferenced != null) { type = dereferenced; } } String qualifiedName = n.getQualifiedName(); if (type.isFunctionPrototypeType() || (type.toObjectType() != null && type.toObjectType().getConstructor() != null)) { return type.toString(); } else if (qualifiedName != null) { return qualifiedName; } else if (type instanceof FunctionType) { // Don't show complex function names. return "function"; } else { return type.toString(); } } /** * This method gets the JSType from the Node argument and verifies that it is * present. */ private JSType getJSType(Node n) { JSType jsType = n.getJSType(); if (jsType == null) { // TODO(user): This branch indicates a compiler bug, not worthy of // halting the compilation but we

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> should log this and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } private JSType getNativeType(JSTypeNative typeId) { return typeRegistry.getNativeType(typeId); } /** * Signals that the first type and the second type have been * used interchangeably. * * Type-based optimizations should take this into account * so that they don't wreck code with type warnings. */ static class TypeMismatch { final JSType typeA; final JSType typeB; /** * It's the responsibility of the class that creates the * {@code TypeMismatch} to ensure that {@code a} and {@code b} are * non-matching types. */ TypeMismatch(JSType a, JSType b) { this.typeA = a; this.typeB = b; } @Override public boolean equals(Object object) { if (object instanceof TypeMismatch) { TypeMismatch that = (TypeMismatch) object; return (that.typeA.equals(this.typeA) && that.typeB.equals(this.typeB)) || (that.typeB.equals(this.typeA) && that.typeA.equals(this.typeB)); } return false; } @Override public int hashCode() { return Objects.hashCode(typeA, typeB); } @Override public String toString() { return "(" + typeA + ", " + typeB + ")"; } } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Override public boolean isNullable() { return false; } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN)) || that.isObject()) { return UNKNOWN; } return FALSE; } @Override public boolean isBooleanValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE); } @Override public String toString() { return "boolean"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseBooleanType(); } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> = def.getValue(); Node inputValue = dominantReplacements.get(defineName); Node finalValue = inputValue != null ? inputValue : info.getLastValue(); if (finalValue != info.initialValue) { info.initialValueParent.replaceChild( info.initialValue, finalValue.cloneTree()); compiler.addToDebugLog("Overriding @define variable " + defineName); changed = changed || finalValue.getType() != info.initialValue.getType() || !finalValue.isEquivalentTo(info.initialValue); } } if (changed) { compiler.reportCodeChange(); } Set<String> unusedReplacements = dominantReplacements.keySet(); unusedReplacements.removeAll(allDefines.keySet()); unusedReplacements.removeAll(KNOWN_DEFINES); for (String unknownDefine : unusedReplacements) { compiler.report(JSError.make(UNKNOWN_DEFINE_WARNING, unknownDefine)); } } private static String format(MessageFormat format, Object... params) { return format.format(params); } /** * Finds all defines, and creates a {@link DefineInfo} data structure for * each one. * @return A map of {@link DefineInfo} structures, keyed by name. */ private Map<String, DefineInfo> collectDefines(Node root, GlobalNamespace namespace) { // Find all the global names with a @define annotation List<Name> allDefines = Lists.newArrayList(); for (Name name : namespace.getNameIndex().values()) { if (name.docInfo != null && name.docInfo.isDefine()) { allDefines.add(name); } else if (name.refs != null) { for (Ref ref : name.refs) { Node n = ref.node; Node parent = ref.node.getParent(); JSDocInfo info = n.getJSDocInfo(); if (info == null && parent.getType() == Token.VAR && parent.hasOneChild()) { info = parent.getJSDocInfo(); } if (info != null && info.isDefine()) { allDefines.add(name); break; } } } } CollectDefines pass = new CollectDefines(compiler, all

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>verse(NodeTraversal nodeTraversal, Node n, Node parent) { updateAssignAllowedStack(n, true); return true; } public void visit(NodeTraversal t, Node n, Node parent) { RefInfo refInfo = allRefInfo.get(n); if (refInfo != null) { Ref ref = refInfo.ref; Name name = refInfo.name; String fullName = name.fullName(); switch (ref.type) { case SET_FROM_GLOBAL: case SET_FROM_LOCAL: Node valParent = getValueParent(ref); Node val = valParent.getLastChild(); if (valParent.getType() == Token.ASSIGN && name.isSimpleName() && name.declaration == ref) { // For defines, it's an error if a simple name is assigned // before it's declared compiler.report( JSError.make(t, val, INVALID_DEFINE_INIT_ERROR, fullName)); } else if (processDefineAssignment(t, fullName, val, valParent)) { // remove the assignment so that the variable is still declared, // but no longer assigned to a value, e.g., // DEF_FOO = 5; // becomes "5;" // We can't remove the ASSIGN/VAR when we're still visiting its // children, so we'll have to come back later to remove it. refInfo.name.removeRef(ref); lvalueToRemoveLater = valParent; } break; default: if (t.inGlobalScope()) { // Treat this as a reference to a define in the global scope. // After this point, the define must not be reassigned, // or it's an error. DefineInfo info = assignableDefines.get(fullName); if (info != null) { setDefineInfoNotAssignable(info, t); assignableDefines.remove(fullName); } } break; } } if (!t.inGlobalScope() && n.getJSDocInfo() != null && n.getJSDocInfo().isDefine()) { // warn about @define annotations in local scopes compiler.report( JSError.make(t, n, NON_GLOBAL_DEFINE_INIT_ERROR, "")); } if

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> (lvalueToRemoveLater == n) { lvalueToRemoveLater = null; if (n.getType() == Token.ASSIGN) { Node last = n.getLastChild(); n.removeChild(last); parent.replaceChild(n, last); } else { Preconditions.checkState(n.getType() == Token.NAME); n.removeChild(n.getFirstChild()); } compiler.reportCodeChange(); } if (n.getType() == Token.CALL) { if (t.inGlobalScope()) { // If there's a function call in the global scope, // we just say it's unsafe and freeze all the defines. // // NOTE(nicksantos): We could be a lot smarter here. For example, // ReplaceOverriddenVars keeps a call graph of all functions and // which functions/variables that they reference, and tries // to statically determine which functions are "safe" and which // are not. But this would be overkill, expecially because // the intended use of defines is with config_files, where // all the defines are at the top of the bundle. for (DefineInfo info : assignableDefines.values()) { setDefineInfoNotAssignable(info, t); } assignableDefines.clear(); } } updateAssignAllowedStack(n, false); } /** * Determines whether assignment to a define should be allowed * in the subtree of the given node, and if not, records that fact. * * @param n The node whose subtree we're about to enter or exit. * @param entering True if we're entering the subtree, false otherwise. */ private void updateAssignAllowedStack(Node n, boolean entering) { switch (n.getType()) { case Token.CASE: case Token.FOR: case Token.FUNCTION: case Token.HOOK: case Token.IF: case Token.SWITCH: case Token.WHILE: if (entering) { assignAllowed.push(0); } else { assignAllowed.remove(); } break; } } /** * Determines whether assignment to a define should be allowed * at the current point of the traversal. */ private boolean isAssignAllowed() { return assignAllowed.element()

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>} until requested by * {@link #getControlFlowGraph()}. Note that {@link ArrayDeque} does not allow * {@code null} elements, so {@link LinkedList} is used instead. */ Deque<ControlFlowGraph<Node>> cfgs = new LinkedList<ControlFlowGraph<Node>>(); /** The current source file name */ private String sourceName; /** The scope creator */ private ScopeCreator scopeCreator; /** Possible callback for scope entry and exist **/ private ScopedCallback scopeCallback; /** * Callback */ public interface Callback { /** * <p>Visits a node in pre order (before visiting its children) and decides * whether this node's children should be traversed. If children are * traversed, they will be visited by * {@link #visit(NodeTraversal, Node, Node)} in post order.</p> * <p>Implementations can have side effects (e.g. modifying the parse * tree).</p> * @return whether the children of this node should be visited */ boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent); /** * <p>Visits a node in post order (after its children have been visited). * A node is visited only if all its parents should be traversed * ({@link #shouldTraverse(NodeTraversal, Node, Node)}).</p> * <p>Implementations can have side effects (e.g. modifying the parse * tree).</p> */ void visit(NodeTraversal t, Node n, Node parent); } /** * Callback that also knows about scope changes */ public interface ScopedCallback extends Callback { /** * Called immediately after entering a new scope. The new scope can * be accessed through t.getScope() */ void enterScope(NodeTraversal t); /** * Called immediately before exiting a scope. The ending scope can * be accessed through t.getScope() */ void exitScope(NodeTraversal t); } /** * Abstract callback to visit all nodes in post order. * */ public abstract static class AbstractPostOrderCallback implements Callback { public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { return true; } } /** * Abstract callback to

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> visit all nodes but not traverse into function * bodies. */ public abstract static class AbstractShallowCallback implements Callback { public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { // We do want to traverse the name of a named function, but we don't // want to traverse the arguments or body. return parent == null || parent.getType() != Token.FUNCTION || n == parent.getFirstChild(); } } /** * Abstract callback to visit all structure and statement nodes but doesn't * traverse into functions or expressions. */ public abstract static class AbstractShallowStatementCallback implements Callback { public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { return parent == null || NodeUtil.isControlStructure(parent) || NodeUtil.isStatementBlock(parent); } } /** * Abstract callback to visit a pruned set of nodes. * */ public abstract static class AbstractNodeTypePruningCallback implements Callback { private final Set<Integer> nodeTypes; private final boolean include; /** * Creates an abstract pruned callback. * @param nodeTypes the nodes to include in the traversal */ public AbstractNodeTypePruningCallback(Set<Integer> nodeTypes) { this(nodeTypes, true); } /** * Creates an abstract pruned callback. * @param nodeTypes the nodes to include/exclude in the traversal * @param include whether to include or exclude the nodes in the traversal */ public AbstractNodeTypePruningCallback(Set<Integer> nodeTypes, boolean include) { this.nodeTypes = nodeTypes; this.include = include; } public boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { return include == nodeTypes.contains(n.getType()); } } /** * Creates a node traversal using the specified callback interface. */ public NodeTraversal(AbstractCompiler compiler, Callback cb) { this(compiler, cb, new SyntacticScopeCreator(compiler)); } /** * Creates a node traversal using the specified callback interface * and the scope creator. */ public NodeTraversal(AbstractCompiler compiler, Callback cb, ScopeCreator scopeCreator) { this.callback = cb;

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> if (cb instanceof ScopedCallback) { this.scopeCallback = (ScopedCallback) cb; } this.compiler = compiler; this.sourceName = ""; this.scopeCreator = scopeCreator; } private void throwUnexpectedException(Exception unexpectedException) { // If there's an unexpected exception, try to get the // line number of the code that caused it. String message = unexpectedException.getMessage(); // TODO(user): It is possible to get more information if curNode or // its parent is missing. We still have the scope stack in which it is still // very useful to find out at least which function caused the exception. if (!sourceName.isEmpty()) { message = unexpectedException.getMessage() + "\n" + formatNodeContext("Node", curNode) + (curNode == null ? "" : formatNodeContext("Parent", curNode.getParent())); } compiler.throwInternalError(message, unexpectedException); } private String formatNodeContext(String label, Node n) { if (n == null) { return " " + label + ": NULL"; } return " " + label + "(" + n.toString(false, false, false) + "): " + formatNodePosition(n); } /** * Traverses a parse tree recursively. */ public void traverse(Node root) { try { sourceName = ""; curNode = root; pushScope(root); traverseBranch(root, null); popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException); } } public void traverseRoots(Node ... roots) { traverseRoots(Lists.newArrayList(roots)); } public void traverseRoots(List<Node> roots) { if (roots.isEmpty()) { return; } try { Node scopeRoot = roots.get(0).getParent(); Preconditions.checkState(scopeRoot != null); sourceName = ""; curNode = scopeRoot; pushScope(scopeRoot); for (Node root : roots) { Preconditions.checkState(root.getParent() == scopeRoot); traverseBranch(root, scopeRoot); } popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>); } } private static final String MISSING_SOURCE = "[source unknown]"; private String formatNodePosition(Node n) { if (n == null) { return MISSING_SOURCE + "\n"; } int lineNumber = n.getLineno(); int columnNumber = n.getCharno(); String src = compiler.getSourceLine(sourceName, lineNumber); if (src == null) { src = MISSING_SOURCE; } return sourceName + ":" + lineNumber + ":" + columnNumber + "\n" + src + "\n"; } /** * Traverses a parse tree recursively with a scope, starting with the given * root. This should only be used in the global scope. Otherwise, use * {@link #traverseAtScope}. */ void traverseWithScope(Node root, Scope s) { Preconditions.checkState(s.isGlobal()); sourceName = ""; curNode = root; pushScope(s); traverseBranch(root, null); popScope(); } /** * Traverses a parse tree recursively with a scope, starting at that scope's * root. */ void traverseAtScope(Scope s) { Node n = s.getRootNode(); if (n.getType() == Token.FUNCTION) { // We need to do some extra magic to make sure that the scope doesn't // get re-created when we dive into the function. sourceName = getSourceName(n); curNode = n; pushScope(s); Node args = n.getFirstChild().getNext(); Node body = args.getNext(); traverseBranch(args, n); traverseBranch(body, n); popScope(); } else { traverseWithScope(n, s); } } /** * Traverses an inner node recursively with a refined scope. An inner node may * be any node with a non {@code null} parent (i.e. all nodes except the * root). * * @param node the node to traverse * @param parent the node's parent, it may be not be {@code null} * @param refinedScope the refined scope of the scope currently at the top of * the scope stack or in trivial cases that very scope or {@

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>fallthrough") private void traverseBranch(Node n, Node parent) { int type = n.getType(); if (type == Token.SCRIPT) { sourceName = getSourceName(n); } curNode = n; if (!callback.shouldTraverse(this, n, parent)) return; switch (type) { case Token.CATCH: Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getFirstChild().getType() == Token.NAME); // the first child is the catch var and the third child // is the code block traverseBranch(n.getFirstChild(), n); traverseBranch(n.getFirstChild().getNext().getNext(), n); break; case Token.FUNCTION: traverseFunction(n, parent); break; default: for (Node child = n.getFirstChild(); child != null; ) { // child could be replaced, in which case our child node // would no longer point to the true next Node next = child.getNext(); traverseBranch(child, n); child = next; } break; } curNode = n; callback.visit(this, n, parent); } /** * Traverses a function. */ private void traverseFunction(Node n, Node parent) { Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getType() == Token.FUNCTION); final Node fnName = n.getFirstChild(); boolean anonymous = parent != null && NodeUtil.isFunctionAnonymous(n); if (!anonymous) { // Named functions are parent of the containing scope. traverseBranch(fnName, n); } curNode = n; pushScope(n); if (anonymous) { // Anonymous function names are parent of the contained scope. traverseBranch(fnName, n); } final Node args = fnName.getNext(); final Node body = args.getNext(); // Args traverseBranch(args, n); // Body Preconditions.checkState(body.getNext() == null && body.getType() == Token.BLOCK); traverseBranch(body, n); popScope(); } /** Examines the functions stack for the last instance of a function node. */

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> the current scope's root. */ public Node getScopeRoot() { if (scopeRoots.isEmpty()) { return scopes.peek().getRootNode(); } else { return scopeRoots.peek(); } } /** * Determines whether the traversal is currently in the global scope. */ boolean inGlobalScope() { return getScopeDepth() <= 1; } int getScopeDepth() { return scopes.size() + scopeRoots.size(); } public boolean hasScope() { return !(scopes.isEmpty() && scopeRoots.isEmpty()); } /** Reports a diagnostic (error or warning) */ public void report(Node n, DiagnosticType diagnosticType, String... arguments) { JSError error = JSError.make(getSourceName(), n, diagnosticType, arguments); compiler.report(error); } private static String getSourceName(Node n) { String name = (String) n.getProp(Node.SOURCENAME_PROP); return name == null ? "" : name; } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>s constants with the IS_CONSTANT_NAME annotation. * * @author johnlenz@google.com (johnlenz) */ // public for ReplaceDebugStringsTest class Normalize implements CompilerPass { private final AbstractCompiler compiler; private final boolean assertOnChange; private static final boolean CONVERT_WHILE_TO_FOR = true; static final boolean MAKE_LOCAL_NAMES_UNIQUE = true; Normalize(AbstractCompiler compiler, boolean assertOnChange) { this.compiler = compiler; this.assertOnChange = assertOnChange; } private void reportCodeChange(String changeDescription) { if (assertOnChange) { throw new IllegalStateException( "Normalize constraints violated:\n" + changeDescription); } compiler.reportCodeChange(); } @Override public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, root, new NormalizeStatements(compiler, assertOnChange)); removeDuplicateDeclarations(root); if (MAKE_LOCAL_NAMES_UNIQUE) { MakeDeclaredNamesUnique renamer = new MakeDeclaredNamesUnique(); NodeTraversal t = new NodeTraversal(compiler, renamer); t.traverseRoots(externs, root); } new PropogateConstantAnnotations(compiler, assertOnChange) .process(externs, root); } public static class PropogateConstantAnnotations extends AbstractPostOrderCallback implements CompilerPass { private final AbstractCompiler compiler; private final boolean assertOnChange; public PropogateConstantAnnotations( AbstractCompiler compiler, boolean forbidChanges) { this.compiler = compiler; this.assertOnChange = forbidChanges; } @Override public void process(Node externs, Node root) { new NodeTraversal(compiler, this).traverseRoots(externs, root); } @Override public void visit(NodeTraversal t, Node n, Node parent) { // Note: Constant properties annotations are not propagated. if (n.getType() == Token.NAME) { if (n.getString().isEmpty()) { return; } JSDocInfo info = null; // Find the JSDocInfo for a top level variable. Var var = t.getScope().getVar(n.getString()); if (var != null) { info = var.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>getJSDocInfo(); } if ((info != null && info.isConstant()) && !n.getBooleanProp(Node.IS_CONSTANT_NAME)) { n.putBooleanProp(Node.IS_CONSTANT_NAME, true); if (assertOnChange) { String name = n.getString(); throw new IllegalStateException( "Unexpected const change.\n" + " name: "+ name + "\n" + " gramps:" + n.getParent().getParent().toStringTree()); } // Even though the AST has changed (an annotation was added), // the annotations are not compared so don't report the change. // reportCodeChange("constant annotation"); } } } } /** * Walk the AST tree and verify that constant names are used consistently. */ static class VerifyConstants extends AbstractPostOrderCallback implements CompilerPass { final private AbstractCompiler compiler; final private boolean checkUserDeclarations; VerifyConstants(AbstractCompiler compiler, boolean checkUserDeclarations) { this.compiler = compiler; this.checkUserDeclarations = checkUserDeclarations; } @Override public void process(Node externs, Node root) { Node externsAndJs = root.getParent(); Preconditions.checkState(externsAndJs != null); Preconditions.checkState(externsAndJs.hasChild(externs)); NodeTraversal.traverseRoots( compiler, Lists.newArrayList(externs, root), this); } private Map<String,Boolean> constantMap = Maps.newHashMap(); @Override public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.NAME) { String name = n.getString(); if (n.getString().isEmpty()) { return; } boolean isConst = n.getBooleanProp(Node.IS_CONSTANT_NAME); if (checkUserDeclarations) { boolean expectedConst = false; if (NodeUtil.isConstantName(n) || compiler.getCodingConvention().isConstant(n.getString())) { expectedConst = true; } else { expectedConst = false; JSDocInfo info = null; Var var = t.getScope().getVar(n.getString()); if (var != null) { info = var.get

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>JSDocInfo(); } if (info != null && info.isConstant()) { expectedConst = true; } else { expectedConst = false; } } if (expectedConst) { Preconditions.checkState(expectedConst == isConst, "The name " + name + " is not annotated as constant."); } else { Preconditions.checkState(expectedConst == isConst, "The name " + name + " should not be annotated as constant."); } } Boolean value = constantMap.get(name); if (value == null) { constantMap.put(name, isConst); } else { Preconditions.checkState(value.booleanValue() == isConst, "The name " + name + " is not consistently annotated as " + "constant."); } } } } /** * Simplify the AST: * - VAR declarations split, so they represent exactly one child * declaration. * - WHILEs are converted to FORs * - FOR loop are initializers are moved out of the FOR structure * - LABEL node of children other than LABEL, BLOCK, WHILE, FOR, or DO are * moved into a block. */ static class NormalizeStatements implements Callback { private final AbstractCompiler compiler; private final boolean assertOnChange; NormalizeStatements(AbstractCompiler compiler, boolean assertOnChange) { this.compiler = compiler; this.assertOnChange = assertOnChange; } private void reportCodeChange(String changeDescription) { if (assertOnChange) { throw new IllegalStateException( "Normalize constraints violated:\n" + changeDescription); } compiler.reportCodeChange(); } @Override public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { doStatementNormalizations(t, n, parent); return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.WHILE: if (CONVERT_WHILE_TO_FOR) { Node expr = n.getFirstChild(); n.setType(Token.FOR); n.addChildBefore(new Node(Token.EMPTY), expr); n.addChildAfter(new Node(Token.EMPTY), expr

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>); reportCodeChange("WHILE node"); } break; } } /** * Do normalizations that introduce new siblings or parents. */ private void doStatementNormalizations( NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.LABEL) { normalizeLabels(n); } // Only inspect the children of SCRIPTs, BLOCKs and LABELs, as all these // are the only legal place for VARs and FOR statements. if (NodeUtil.isStatementBlock(n) || n.getType() == Token.LABEL) { extractForInitializer(n, null, null); } // Only inspect the children of SCRIPTs, BLOCKs, as all these // are the only legal place for VARs. if (NodeUtil.isStatementBlock(n)) { splitVarDeclarations(n); } if (n.getType() == Token.FUNCTION) { moveNamedFunctions(n.getLastChild()); } } // TODO(johnlenz): Move this to NodeTypeNormalizer once the unit tests are // fixed. /** * Limit the number of special cases where LABELs need to be handled. Only * BLOCK and loops are allowed to be labeled. Loop labels must remain in * place as the named continues are not allowed for labeled blocks. */ private void normalizeLabels(Node n) { Preconditions.checkArgument(n.getType() == Token.LABEL); Node last = n.getLastChild(); switch (last.getType()) { case Token.LABEL: case Token.BLOCK: case Token.FOR: case Token.WHILE: case Token.DO: return; default: Node block = new Node(Token.BLOCK); n.replaceChild(last, block); block.addChildToFront(last); reportCodeChange("LABEL normalization"); return; } } /** * Bring the initializers out of FOR loops. These need to be placed * before any associated LABEL nodes. This needs to be done from the top * level label first so this is called as a pre-order callback (from * shouldTraverse). * * @param n The node to inspect. * @param before The node to insert the initializer before. *

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> @param beforeParent The parent of the node before which the initializer * will be inserted. */ private void extractForInitializer( Node n, Node before, Node beforeParent) { for (Node next, c = n.getFirstChild(); c != null; c = next) { next = c.getNext(); Node insertBefore = (before == null) ? c : before; Node insertBeforeParent = (before == null) ? n : beforeParent; switch (c.getType()) { case Token.LABEL: extractForInitializer(c, insertBefore, insertBeforeParent); break; case Token.FOR: if (!NodeUtil.isForIn(c) && c.getFirstChild().getType() != Token.EMPTY) { Node init = c.getFirstChild(); c.replaceChild(init, new Node(Token.EMPTY)); Node newStatement; // Only VAR statements, and expressions are allowed, // but are handled differently. if (init.getType() == Token.VAR) { newStatement = init; } else { newStatement = NodeUtil.newExpr(init); } insertBeforeParent.addChildBefore(newStatement, insertBefore); reportCodeChange("FOR initializer"); } break; } } } /** * Split a var node such as: * var a, b; * into individual statements: * var a; * var b; * @param n The whose children we should inspect. */ private void splitVarDeclarations(Node n) { for (Node next, c = n.getFirstChild(); c != null; c = next) { next = c.getNext(); if (c.getType() == Token.VAR) { if (assertOnChange && !c.hasChildren()) { throw new IllegalStateException("Empty VAR node."); } while (c.getFirstChild() != c.getLastChild()) { Node name = c.getFirstChild(); c.removeChild(name); Node newVar = new Node( Token.VAR, name, n.getLineno(), n.getCharno()); n.addChildBefore(newVar, c); reportCodeChange("VAR with multiple children"); } } } } /** * Move all the functions that are valid

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> { /** * Remove duplicate VAR declarations encountered discovered during * scope creation. */ @Override public void onRedeclaration( Scope s, String name, Node n, Node parent, Node gramps, Node nodeWithLineNumber) { Preconditions.checkState(n.getType() == Token.NAME); if (parent.getType() == Token.VAR) { Preconditions.checkState(parent.hasOneChild()); // // Remove the parent VAR. There are three cases that need to be handled: // 1) "var a = b;" which is replaced with "a = b" // 2) "label:var a;" which is replaced with "label:;". Ideally, the // label itself would be removed but that is not possible in the // context in which "onRedeclaration" is called. // 3) "for (var a in b) ..." which is replaced with "for (a in b)..." // Cases we don't need to handle are VARs with multiple children, // which have already been split into separate declarations, so there // is no need to handle that here, and "for (var a;;);", which has // been moved out of the loop. // // The result of this is that in each case the parent node is replaced // which is generally dangerous in a traversal but is fine here with // the scope creator, as the next node of interest is the parent's // next sibling. // if (n.hasChildren()) { // The var is being initialize, preserve the new value. parent.removeChild(n); // Convert "var name = value" to "name = value" Node value = n.getFirstChild(); n.removeChild(value); Node replacement = new Node(Token.ASSIGN, n, value); gramps.replaceChild(parent, new Node(Token.EXPR_RESULT, replacement)); } else { // It is an empty reference remove it. if (NodeUtil.isStatementBlock(gramps)) { gramps.removeChild(parent); } else if (gramps.getType() == Token.FOR) { // This is the "for (var a in b)..." case. We don't need to worry // about initializers in "for (

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>var a;;)..." as those are moved out // as part of the other normalizations. parent.removeChild(n); gramps.replaceChild(parent, n); } else { Preconditions.checkState(gramps.getType() == Token.LABEL); gramps.replaceChild(parent, new Node(Token.EMPTY)); } } reportCodeChange("Duplicate VAR declaration"); } } } /** * A simple class that causes scope to be created. */ private final class ScopeTicklingCallback implements NodeTraversal.ScopedCallback { @Override public void enterScope(NodeTraversal t) { // Cause the scope to be created, which will cause duplicate // to be found. t.getScope(); } @Override public void exitScope(NodeTraversal t) { // Nothing to do. } @Override public boolean shouldTraverse( NodeTraversal nodeTraversal, Node n, Node parent) { return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) { // Nothing to do. } } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isStringValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return "string"; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.STRING_OBJECT_TYPE); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseStringType(); } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>[--i] = null; } keyCount = 0; occupiedCount = 0; } public Iterator newIterator() { return new Iterator(this); } // The sole purpose of the method is to avoid accessing private fields // from the Iterator inner class to workaround JDK 1.1 compiler bug which // generates code triggering VerifierError on recent JVMs final void initIterator(Iterator i) { i.init(keys, values, keyCount); } /** Return array of present keys */ public Object[] getKeys() { Object[] array = new Object[keyCount]; getKeys(array, 0); return array; } public void getKeys(Object[] array, int offset) { int count = keyCount; for (int i = 0; count != 0; ++i) { Object key = keys[i]; if (key != null && key != DELETED) { if (key == UniqueTag.NULL_VALUE) { key = null; } array[offset] = key; ++offset; --count; } } } private static int tableLookupStep(int fraction, int mask, int power) { int shift = 32 - 2 * power; if (shift >= 0) { return ((fraction >>> shift) & mask) | 1; } else { return (fraction & (mask >>> -shift)) | 1; } } private int findIndex(Object key) { if (keys != null) { int hash = key.hashCode(); int fraction = hash * A; int index = fraction >>> (32 - power); Object test = keys[index]; if (test != null) { int N = 1 << power; if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } // Search in table after first failed attempt int mask = N - 1; int step = tableLookupStep(fraction, mask, power); int n = 0; for (;;) { if (check) { if (n >= occupiedCount) Kit.codeBug(); ++n; } index = (index + step) & mask

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>; test = keys[index]; if (test == null) { break; } if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } } } } return -1; } // Insert key that is not present to table without deleted entries // and enough free space private int insertNewKey(Object key, int hash) { if (check && occupiedCount != keyCount) Kit.codeBug(); if (check && keyCount == 1 << power) Kit.codeBug(); int fraction = hash * A; int index = fraction >>> (32 - power); int N = 1 << power; if (keys[index] != null) { int mask = N - 1; int step = tableLookupStep(fraction, mask, power); int firstIndex = index; do { if (check && keys[index] == DELETED) Kit.codeBug(); index = (index + step) & mask; if (check && firstIndex == index) Kit.codeBug(); } while (keys[index] != null); } keys[index] = key; values[N + index] = hash; ++occupiedCount; ++keyCount; return index; } private void rehashTable() { if (keys == null) { if (check && keyCount != 0) Kit.codeBug(); if (check && occupiedCount != 0) Kit.codeBug(); int N = 1 << power; keys = new Object[N]; values = new int[2 * N]; } else { // Check if removing deleted entries would free enough space if (keyCount * 2 >= occupiedCount) { // Need to grow: less then half of deleted entries ++power; } int N = 1 << power; Object[] oldKeys = keys; int[] oldValues = values; int oldN = oldKeys.length; keys = new Object[N]; values = new int[2 * N]; int remaining = keyCount; occupiedCount = keyCount = 0; for (int i = 0; remaining != 0; ++i) {

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> Object key = oldKeys[i]; if (key != null && key != DELETED) { int keyHash = oldValues[oldN + i]; int index = insertNewKey(key, keyHash); values[index] = oldValues[i]; --remaining; } } } } // Ensure key index creating one if necessary private int ensureIndex(Object key) { int hash = key.hashCode(); int index = -1; int firstDeleted = -1; if (keys != null) { int fraction = hash * A; index = fraction >>> (32 - power); Object test = keys[index]; if (test != null) { int N = 1 << power; if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } if (test == DELETED) { firstDeleted = index; } // Search in table after first failed attempt int mask = N - 1; int step = tableLookupStep(fraction, mask, power); int n = 0; for (;;) { if (check) { if (n >= occupiedCount) Kit.codeBug(); ++n; } index = (index + step) & mask; test = keys[index]; if (test == null) { break; } if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } if (test == DELETED && firstDeleted < 0) { firstDeleted = index; } } } } // Inserting of new key if (check && keys != null && keys[index] != null) Kit.codeBug(); if (firstDeleted >= 0) { index = firstDeleted; } else { // Need to consume empty entry: check occupation level if (keys == null || occupiedCount * 4 >= (1 << power) * 3) { // Too litle unused entries: rehash rehashTable(); return insertNewKey(key, hash); } ++occupiedCount; } keys[index] = key; values[(1 << power) +

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>int i = 0; i != N; ++i) { Object current = getImpl(i); if (current == obj || (current != null && current.equals(obj))) { return i; } } return -1; } public int lastIndexOf(Object obj) { for (int i = size; i != 0;) { --i; Object current = getImpl(i); if (current == obj || (current != null && current.equals(obj))) { return i; } } return -1; } public final Object peek() { int N = size; if (N == 0) throw onEmptyStackTopRead(); return getImpl(N - 1); } @SuppressWarnings("fallthrough") public final Object pop() { if (sealed) throw onSeledMutation(); int N = size; --N; Object top; switch (N) { case -1: throw onEmptyStackTopRead(); case 0: top = f0; f0 = null; break; case 1: top = f1; f1 = null; break; case 2: top = f2; f2 = null; break; case 3: top = f3; f3 = null; break; case 4: top = f4; f4 = null; break; default: top = data[N - FIELDS_STORE_SIZE]; data[N - FIELDS_STORE_SIZE] = null; } size = N; return top; } public final void push(Object value) { add(value); } public final void add(Object value) { if (sealed) throw onSeledMutation(); int N = size; if (N >= FIELDS_STORE_SIZE) { ensureCapacity(N + 1); } size = N + 1; setImpl(N, value); } @SuppressWarnings("fallthrough") public final void add(int index, Object value) { int N = size; if (!(0 <= index && index <= N)) throw onInvalidIndex(index, N + 1); if (sealed) throw onSeledMutation(); Object

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>IN_EXTERNS_ERROR = DiagnosticType.warning( "JSC_NAME_REFERENCE_IN_EXTERNS", "accessing name {0} in externs has no effect"); static final DiagnosticType INVALID_FUNCTION_DECL = DiagnosticType.error("JSC_INVALID_FUNCTION_DECL", "Syntax error: function declaration must have a name"); private CompilerInput synthesizedExternsInput = null; private Node synthesizedExternsRoot = null; private final AbstractCompiler compiler; // Whether this is the post-processing sanity check. private final boolean sanityCheck; VarCheck(AbstractCompiler compiler) { this(compiler, false); } VarCheck(AbstractCompiler compiler, boolean sanityCheck) { this.compiler = compiler; this.sanityCheck = sanityCheck; } /** {@inheritDoc} */ public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, externs, new NameRefInExternsCheck()); NodeTraversal.traverseRoots( compiler, Lists.newArrayList(externs, root), this); } /** {@inheritDoc} */ public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() != Token.NAME) { return; } if (NodeUtil.isLabelName(n)) { return; } String varName = n.getString(); // Only a function can have an empty name. if (varName.isEmpty()) { Preconditions.checkState(NodeUtil.isFunction(parent)); // A function declaration with an empty name passes Rhino, // but is supposed to be a syntax error according to the spec. if (!NodeUtil.isAnonymousFunction(parent)) { t.report(n, INVALID_FUNCTION_DECL); } return; } // Check that the var has been declared. Scope scope = t.getScope(); Scope.Var var = scope.getVar(varName); if (var == null) { if (NodeUtil.isAnonymousFunction(parent)) { // e.g. [ function foo() {} ], it's okay if "foo" isn't defined in the // current scope. } else { t.report(n, UNDEFINED_VAR_ERROR, varName); if

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> (sanityCheck) { throw new IllegalStateException("Unexpected variable " + varName); } else { // Create a new variable in a synthetic script. This will prevent // subsequent compiler passes from crashing. Node nameNode = Node.newString(Token.NAME, varName); getSynthesizedExternsRoot().addChildToBack( new Node(Token.VAR, nameNode)); scope.getGlobalScope().declare(varName, nameNode, null, getSynthesizedExternsInput()); } } return; } CompilerInput currInput = t.getInput(); CompilerInput varInput = var.input; if (currInput == varInput || currInput == null || varInput == null) { // The variable was defined in the same file. This is fine. return; } // Check module dependencies. JSModule currModule = currInput.getModule(); JSModule varModule = varInput.getModule(); JSModuleGraph moduleGraph = compiler.getModuleGraph(); if (varModule != currModule && varModule != null && currModule != null) { if (moduleGraph.dependsOn(currModule, varModule)) { // The module dependency was properly declared. } else { if (!sanityCheck && scope.isGlobal()) { if (moduleGraph.dependsOn(varModule, currModule)) { // The variable reference violates a declared module dependency. t.report(n, VIOLATED_MODULE_DEP_ERROR, currModule.getName(), varModule.getName(), varName); } else { // The variable reference is between two modules that have no // dependency relationship. This should probably be considered an // error, but just issue a warning for now. t.report(n, MISSING_MODULE_DEP_ERROR, currModule.getName(), varModule.getName(), varName); } } else { t.report(n, STRICT_MODULE_DEP_ERROR, currModule.getName(), varModule.getName(), varName); } } } } /** * A check for name references in the externs inputs. These used to prevent * a variable from getting renamed, but no longer have any effect. */ private class NameRefInExternsCheck extends AbstractPostOrderCallback { public void visit(

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.NAME) { switch (parent.getType()) { case Token.VAR: case Token.FUNCTION: case Token.GETPROP: case Token.LP: // These are okay. break; default: t.report(n, NAME_REFERENCE_IN_EXTERNS_ERROR, n.getString()); break; } } } } /** Lazily create a "new" externs input for undeclared variables. */ private CompilerInput getSynthesizedExternsInput() { if (synthesizedExternsInput == null) { synthesizedExternsInput = compiler.newExternInput("{SyntheticVarsDeclar}"); } return synthesizedExternsInput; } /** Lazily create a "new" externs root for undeclared variables. */ private Node getSynthesizedExternsRoot() { if (synthesizedExternsRoot == null) { CompilerInput synthesizedExterns = getSynthesizedExternsInput(); synthesizedExternsRoot = synthesizedExterns.getAstRoot(compiler); } return synthesizedExternsRoot; } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> { private static final long serialVersionUID = 1L; VoidType(JSTypeRegistry registry) { super(registry); } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isSubtype(this) || that.isSubtype(getNativeType(JSTypeNative.NULL_TYPE))) { return TRUE; } return FALSE; } @Override public boolean matchesNumberContext() { return false; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public boolean isVoidType() { return true; } @Override public String toString() { return "undefined"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseVoidType(); } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> given name or null if none. */ public CompilerInput getByName(String name) { for (CompilerInput input : inputs) { if (name.equals(input.getName())) { return input; } } return null; } /** * Removes any input with the given name. Returns whether any were removed. */ public boolean removeByName(String name) { boolean found = false; Iterator<CompilerInput> iter = inputs.iterator(); while (iter.hasNext()) { CompilerInput file = iter.next(); if (name.equals(file.getName())) { iter.remove(); file.setModule(null); found = true; } } return found; } /** Returns the module name (primarily for debugging). */ @Override public String toString() { return name; } /** * Removes any references to nodes of the AST. This method is needed to * allow the ASTs to be garbage collected if the modules are kept around. */ public void clearAsts() { for (CompilerInput input : inputs) { input.clearAst(); } } /** * Puts the JS files into a topologically sorted order by their dependencies. */ public void sortInputsByDeps(Compiler compiler) { // Collect all symbols provided in these files. final Map<String, CompilerInput> provides = Maps.newHashMap(); for (CompilerInput input : inputs) { for (String provide : input.getProvides(compiler)) { provides.put(provide, input); } } // Put the files into topologically sorted order by their requires. // NOTE: This will leave the list unchanged if the files are already // topologically sorted. This is important to apps whose dependencies // are incomplete. List<CompilerInput> list = Lists.newArrayList(); Set<CompilerInput> set = Sets.newHashSet(); for (CompilerInput input : inputs) { addInputAndDeps(input, provides, compiler, list, set, Sets.<CompilerInput>newHashSet()); } // Update the JSModule to this order. Preconditions.checkState(inputs.size() == list.size()); inputs.clear(); inputs.addAll(list); } /** *

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> qualifiedName = node.getQualifiedName(); Preconditions.checkNotNull(qualifiedName); JSType origType = node.getJSType(); origType = origType == null ? getNativeType(UNKNOWN_TYPE) : origType; scope.inferQualifiedSlot(qualifiedName, origType, type); break; default: throw new IllegalArgumentException("Node cannot be refined."); } } /** * @see #getRestrictedWithoutUndefined(JSType) */ private final Visitor<JSType> restrictUndefinedVisitor = new Visitor<JSType>() { public JSType caseEnumElementType(EnumElementType enumElementType) { JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } public JSType caseAllType() { return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, NULL_TYPE); } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return getNativeType(NULL_TYPE); } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseUnionType(UnionType type) { return type.getRestrictedUnion(getNativeType(VOID_TYPE)); } public JSType caseUnknownType() { return getNativeType(UNKNOWN_TYPE); } public JSType caseVoidType() { return null; } }; /** * @see #getRestrictedWithoutNull(JSType) */ private final Visitor<JSType> restrictNullVisitor = new Visitor<JSType>() { public JSType caseEnumElementType(EnumElementType enumElementType)

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> { JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } public JSType caseAllType() { return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, VOID_TYPE); } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return null; } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseUnionType(UnionType type) { return type.getRestrictedUnion(getNativeType(NULL_TYPE)); } public JSType caseUnknownType() { return getNativeType(UNKNOWN_TYPE); } public JSType caseVoidType() { return getNativeType(VOID_TYPE); } }; /** * A class common to all visitors that need to restrict the type based on * {@code typeof}-like conditions. */ abstract class RestrictByTypeOfResultVisitor implements Visitor<JSType> { /** * Abstracts away the similarities between visiting the unknown type and the * all type. * @param topType {@code UNKNOWN_TYPE} or {@code ALL_TYPE} * @return the restricted type * @see #caseAllType * @see #caseUnknownType */ protected abstract JSType caseTopType(JSType topType); public JSType caseAllType() { return caseTopType(getNativeType(ALL_TYPE)); } public JSType caseUnknownType() { return caseTopType(getNativeType(UNKNOWN_TYPE)); } public JSType caseUnionType

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>(UnionType type) { JSType restricted = null; for (JSType alternate : type.getAlternates()) { JSType restrictedAlternate = alternate.visit(this); if (restrictedAlternate != null) { if (restricted == null) { restricted = restrictedAlternate; } else { restricted = restrictedAlternate.getLeastSupertype(restricted); } } } return restricted; } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseEnumElementType(EnumElementType enumElementType) { // NOTE(nicksantos): This is a white lie. Suppose we have: // /** @enum {string|number} */ var MyEnum = ...; // if (goog.isNumber(myEnumInstance)) { // /* what is myEnumInstance here? */ // } // There is no type that represents {MyEnum - string}. What we really // need is a notion of "enum subtyping", so that we could dynamically // create a subtype of MyEnum restricted by string. In any case, // this should catch the common case. JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } } /** * A class common to all visitors that need to restrict the type based on * some {@code typeof}-like condition being true. All base cases return * {@code null}. It is up to the subclasses to override the appropriate ones. */ abstract class RestrictByTrueTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { public JSType caseNoObjectType() { return null; } public JSType caseBooleanType() { return null; } public JSType caseFunctionType(FunctionType type) { return null; } public JSType caseNullType() { return null; } public JSType caseNumberType() { return null; } public JSType caseObjectType(ObjectType type) { return null; } public JSType caseStringType() { return null; } public JSType caseVoidType() { return null; } } /** * A

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> class common to all visitors that need to restrict the type based on * some {@code typeof}-like condition being false. All base cases return * their type. It is up to the subclasses to override the appropriate ones. */ abstract class RestrictByFalseTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { @Override protected JSType caseTopType(JSType topType) { return topType; } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return getNativeType(NULL_TYPE); } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseVoidType() { return getNativeType(VOID_TYPE); } } /** * @see ChainableReverseAbstractInterpreter#getRestrictedByTypeOfResult */ private class RestrictByOneTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { /** * A value known to be equal or not equal to the result of the * {@code typeOf} operation. */ private final String value; /** * {@code true} if the {@code typeOf} result is known to equal * {@code value}; {@code false} if it is known <em>not</em> to equal * {@code value}. */ private final boolean resultEqualsValue; RestrictByOneTypeOfResultVisitor(String value, boolean resultEqualsValue) { this.value = value; this.resultEqualsValue = resultEqualsValue; } /** * Computes whether the given result of a {@code typeof} operator matches * expectations, i.e. whether a type that gives such a result should be * kept. */ private boolean matchesExpectation(String result) { return result.equals(value) == resultEqualsValue; } @Override protected JSType caseTopType(JSType topType) { if (

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>resultEqualsValue) { if (value.equals("number")) { return getNativeType(NUMBER_TYPE); } else if (value.equals("boolean")) { return getNativeType(BOOLEAN_TYPE); } else if (value.equals("string")) { return getNativeType(STRING_TYPE); } else if (value.equals("undefined")) { return getNativeType(VOID_TYPE); } else if (value.equals("function")) { return getNativeType(U2U_CONSTRUCTOR_TYPE); } } return topType; } public JSType caseNoObjectType() { return (value.equals("object") || value.equals("function")) == resultEqualsValue ? getNativeType(NO_OBJECT_TYPE) : null; } public JSType caseBooleanType() { return matchesExpectation("boolean") ? getNativeType(BOOLEAN_TYPE) : null; } public JSType caseFunctionType(FunctionType type) { return matchesExpectation("function") ? type : null; } public JSType caseNullType() { return matchesExpectation("object") ? getNativeType(NULL_TYPE) : null; } public JSType caseNumberType() { return matchesExpectation("number") ? getNativeType(NUMBER_TYPE) : null; } public JSType caseObjectType(ObjectType type) { if (value.equals("function")) { JSType ctorType = getNativeType(U2U_CONSTRUCTOR_TYPE); return resultEqualsValue && ctorType.isSubtype(type) ? ctorType : null; } return matchesExpectation("object") ? type : null; } public JSType caseStringType() { return matchesExpectation("string") ? getNativeType(STRING_TYPE) : null; } public JSType caseVoidType() { return matchesExpectation("undefined") ? getNativeType(VOID_TYPE) : null; } } /** * Returns a version of type where undefined is not present. */ final JSType getRestrictedWithoutUndefined(JSType type) { return type == null ? null : type.visit(restrictUndefinedVisitor); } /** * Returns a version of type where null is not present. */ final JSType getRestrictedWithoutNull(JSType type) { return

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> != null) { check(externsRoot, true); } check(jsRoot, false); potentialChecks.flush(); } /** Main entry point of this phase for testing code. */ public Scope processForTesting(Node externsRoot, Node jsRoot) { Preconditions.checkState(scopeCreator == null); Preconditions.checkState(topScope == null); Preconditions.checkState(jsRoot.getParent() != null); Node externsAndJsRoot = jsRoot.getParent(); scopeCreator = new MemoizedScopeCreator(new TypedScopeCreator(compiler)); topScope = scopeCreator.createScope(externsAndJsRoot, null); TypeInferencePass inference = new TypeInferencePass(compiler, reverseInterpreter, topScope, scopeCreator); inference.process(externsRoot, jsRoot); process(externsRoot, jsRoot); return topScope; } public void check(Node node, boolean externs) { Preconditions.checkNotNull(node); NodeTraversal t = new NodeTraversal(compiler, this, scopeCreator); inExterns = externs; t.traverseWithScope(node, topScope); if (externs) { inferJSDocInfo.process(node, null); } else { inferJSDocInfo.process(null, node); } } public boolean shouldTraverse( NodeTraversal t, Node n, Node parent) { JSDocInfo info; switch (n.getType()) { case Token.SCRIPT: case Token.VAR: // @notypecheck info = n.getJSDocInfo(); if (info != null && info.isNoTypeCheck()) { return false; } break; case Token.FUNCTION: // @notypecheck info = n.getJSDocInfo(); info = (info == null) ? parent.getJSDocInfo() : info; if (info != null && info.isNoTypeCheck()) { return false; } // normal type checking final TypeCheck outerThis = this; final Scope outerScope = t.getScope(); final FunctionType functionType = (FunctionType) n.getJSType(); final String functionPrivateName = n.getFirstChild().getString(); if (functionPrivateName != null

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> && functionPrivateName.length() > 0 && outerScope.isDeclared(functionPrivateName, false) && // Ideally, we would want to check whether the type in the scope // differs from the type being defined, but then the extern // redeclarations of built-in types generates spurious warnings. !(outerScope.getVar( functionPrivateName).getType() instanceof FunctionType)) { t.report(n, FUNCTION_MASKS_VARIABLE, functionPrivateName); } // TODO(user): Only traverse the function's body. The function's // name and arguments are traversed by the scope creator, and ideally // should not be traversed by the type checker. break; } return true; } /** * This is the meat of the type checking. It is basically one big switch, * with each case representing one type of parse tree node. The individual * cases are usually pretty straightforward. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. * @param parent The parent of the node n. */ public void visit(NodeTraversal t, Node n, Node parent) { JSType childType; JSType leftType, rightType; Node left, right; // To be explicitly set to false if the node is not typeable. boolean typeable = true; switch (n.getType()) { case Token.NAME: typeable = visitName(t, n, parent); break; case Token.LP: // If this is under a FUNCTION node, it is a parameter list and can be // ignored here. if (parent.getType() != Token.FUNCTION) { ensureTyped(t, n, getJSType(n.getFirstChild())); } else { typeable = false; } break; case Token.COMMA: ensureTyped(t, n, getJSType(n.getLastChild())); break; case Token.TRUE: case Token.FALSE: ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.THIS: ensureTyped(t, n, t.getScope().getTypeOfThis());

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> break; case Token.REF_SPECIAL: ensureTyped(t, n); break; case Token.GET_REF: ensureTyped(t, n, getJSType(n.getFirstChild())); break; case Token.NULL: ensureTyped(t, n, NULL_TYPE); break; case Token.NUMBER: if (n.getParent().getType() != Token.OBJECTLIT) { ensureTyped(t, n, NUMBER_TYPE); } else { typeable = false; } break; case Token.ARRAYLIT: ensureTyped(t, n, ARRAY_TYPE); break; case Token.STRING: if (n.getParent().getType() != Token.OBJECTLIT) { ensureTyped(t, n, STRING_TYPE); } else { typeable = false; } break; case Token.REGEXP: ensureTyped(t, n, REGEXP_TYPE); break; case Token.GETPROP: visitGetProp(t, n, parent); typeable = !(parent.getType() == Token.ASSIGN && parent.getFirstChild() == n); break; case Token.GETELEM: visitGetElem(t, n); // The type of GETELEM is always unknown, so no point counting that. // If that unknown leaks elsewhere (say by an assignment to another // variable), then it will be counted. typeable = false; break; case Token.VAR: visitVar(t, n); typeable = false; break; case Token.NEW: visitNew(t, n); typeable = true; break; case Token.CALL: visitCall(t, n); typeable = !NodeUtil.isExpressionNode(parent); break; case Token.RETURN: visitReturn(t, n); typeable = false; break; case Token.DEC: case Token.INC: left = n.getFirstChild(); validator.expectNumber( t, left, getJSType(left), "increment/decrement"); ensureTyped(t, n, NUMBER_TYPE); break; case Token.NOT: ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.VOID:

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> ensureTyped(t, n, VOID_TYPE); break; case Token.TYPEOF: ensureTyped(t, n, STRING_TYPE); break; case Token.BITNOT: childType = getJSType(n.getFirstChild()); if (!childType.matchesInt32Context()) { t.report(n, BIT_OPERATION, NodeUtil.opToStr(n.getType()), childType.toString()); } ensureTyped(t, n, NUMBER_TYPE); break; case Token.POS: case Token.NEG: left = n.getFirstChild(); validator.expectNumber(t, left, getJSType(left), "sign operator"); ensureTyped(t, n, NUMBER_TYPE); break; case Token.EQ: case Token.NE: { leftType = getJSType(n.getFirstChild()); rightType = getJSType(n.getLastChild()); JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined(); JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined(); TernaryValue result = leftTypeRestricted.testForEquality(rightTypeRestricted); if (result != TernaryValue.UNKNOWN) { if (n.getType() == Token.NE) { result = result.not(); } t.report(n, DETERMINISTIC_TEST, leftType.toString(), rightType.toString(), result.toString()); } ensureTyped(t, n, BOOLEAN_TYPE); break; } case Token.SHEQ: case Token.SHNE: { leftType = getJSType(n.getFirstChild()); rightType = getJSType(n.getLastChild()); JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined(); JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined(); if (!leftTypeRestricted.canTestForShallowEqualityWith( rightTypeRestricted)) { t.report(n, DETERMINISTIC_TEST_NO_RESULT, leftType.toString(), rightType.toString()); } ensureTyped(t, n, BOOLEAN_TYPE); break; } case Token.LT: case Token.LE: case Token.GT: case Token.GE: left

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Type = getJSType(n.getFirstChild()); rightType = getJSType(n.getLastChild()); if (rightType.isNumber()) { validator.expectNumber( t, n, leftType, "left side of numeric comparison"); } else if (leftType.isNumber()) { validator.expectNumber( t, n, rightType, "right side of numeric comparison"); } else if (leftType.matchesNumberContext() && rightType.matchesNumberContext()) { // OK. } else { // Whether the comparison is numeric will be determined at runtime // each time the expression is evaluated. Regardless, both operands // should match a string context. String message = "left side of comparison"; validator.expectString(t, n, leftType, message); validator.expectNotVoid( t, n, leftType, message, getNativeType(STRING_TYPE)); message = "right side of comparison"; validator.expectString(t, n, rightType, message); validator.expectNotVoid( t, n, rightType, message, getNativeType(STRING_TYPE)); } ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.IN: left = n.getFirstChild(); right = n.getLastChild(); leftType = getJSType(left); rightType = getJSType(right); validator.expectObject(t, n, rightType, "'in' requires an object"); validator.expectString(t, left, leftType, "left side of 'in'"); ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.INSTANCEOF: left = n.getFirstChild(); right = n.getLastChild(); leftType = getJSType(left); rightType = getJSType(right).restrictByNotNullOrUndefined(); validator.expectAnyObject( t, left, leftType, "deterministic instanceof yields false"); validator.expectActualObject( t, right, rightType, "instanceof requires an object"); ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.ASSIGN: visitAssign(t, n); typeable = false; break; case Token.ASSIGN_LSH: case Token.ASSIGN

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>_RSH: case Token.ASSIGN_URSH: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_SUB: case Token.ASSIGN_ADD: case Token.ASSIGN_MUL: case Token.LSH: case Token.RSH: case Token.URSH: case Token.DIV: case Token.MOD: case Token.BITOR: case Token.BITXOR: case Token.BITAND: case Token.SUB: case Token.ADD: case Token.MUL: visitBinaryOperator(n.getType(), t, n); break; case Token.DELPROP: if (!isReference(n.getFirstChild())) { t.report(n, BAD_DELETE); } ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.CASE: JSType switchType = getJSType(parent.getFirstChild()); JSType caseType = getJSType(n.getFirstChild()); validator.expectSwitchMatchesCase(t, n, switchType, caseType); typeable = false; break; case Token.WITH: { Node child = n.getFirstChild(); childType = getJSType(child); validator.expectObject( t, child, childType, "with requires an object"); typeable = false; break; } case Token.FUNCTION: visitFunction(t, n); break; // These nodes have no interesting type behavior. case Token.LABEL: case Token.SWITCH: case Token.BREAK: case Token.CATCH: case Token.TRY: case Token.SCRIPT: case Token.EXPR_RESULT: case Token.BLOCK: case Token.EMPTY: case Token.DEFAULT: case Token.CONTINUE: case Token.DEBUGGER: case Token.THROW: typeable = false; break; // These nodes require data flow analysis. case Token.DO: case Token.FOR: case Token.IF: case Token.WHILE: typeable = false; break; // These nodes are typed during the type inference. case Token

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>.AND: case Token.HOOK: case Token.OBJECTLIT: case Token.OR: if (n.getJSType() != null) { // If we didn't run type inference. ensureTyped(t, n); } else { // If this is an enum, then give that type to the objectlit as well. if ((n.getType() == Token.OBJECTLIT) && (parent.getJSType() instanceof EnumType)) { ensureTyped(t, n, parent.getJSType()); } else { ensureTyped(t, n); } } break; default: t.report(n, UNEXPECTED_TOKEN, Token.name(n.getType())); ensureTyped(t, n); break; } // Don't count externs since the user's code may not even use that part. typeable = typeable && !inExterns; if (typeable) { doPercentTypedAccounting(t, n); } } /** * Counts the given node in the typed statistics. * @param n a node that should be typed */ private void doPercentTypedAccounting(NodeTraversal t, Node n) { JSType type = n.getJSType(); if (type == null) { nullCount++; } else if (type.isUnknownType()) { if (reportUnknownTypes.isOn()) { String unresolvedReference = getUnresolvedReference(type); if (unresolvedReference != null) { compiler.report(JSError.make(t, n, reportUnknownTypes, UNRESOLVED_TYPE, unresolvedReference)); } else { compiler.report(JSError.make(t, n, reportUnknownTypes, UNKNOWN_EXPR_TYPE)); } } unknownCount++; } else { typedCount++; } } /** * Looks through the type to see if it contains an unresolved reference. This * is often the reason that a type is unresolved, and it can occur because of * a simple misspelling of a type name. */ private String getUnresolvedReference(JSType type) { if (type.isNamedType()) { NamedType namedType = (NamedType) type; if (!namedType.is

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Resolved()) { return namedType.getReferenceName(); } } else if (type.isUnionType()) { for (JSType alt : ((UnionType) type).getAlternates()) { if (alt.isUnknownType()) { String unresolvedReference = getUnresolvedReference(alt); if (unresolvedReference != null) { return unresolvedReference; } } } } return null; } /** * Visits an assignment <code>lvalue = rvalue</code>. If the * <code>lvalue</code> is a prototype modification, we change the schema * of the object type it is referring to. * @param t the traversal * @param assign the assign node * (<code>assign.getType() == Token.ASSIGN</code> is an implicit invariant) */ private void visitAssign(NodeTraversal t, Node assign) { JSDocInfo info = assign.getJSDocInfo(); Node lvalue = assign.getFirstChild(); Node rvalue = assign.getLastChild(); if (lvalue.getType() == Token.GETPROP) { Node object = lvalue.getFirstChild(); JSType objectJsType = getJSType(object); String property = lvalue.getLastChild().getString(); // the first name in this getprop refers to an interface // we perform checks in addition to the ones below if (object.getType() == Token.GETPROP) { JSType jsType = getJSType(object.getFirstChild()); if (jsType.isInterface() && object.getLastChild().getString().equals("prototype")) { visitInterfaceGetprop(t, assign, object, property, lvalue, rvalue); } } // /** @type ... */object.name = ...; if (info != null && info.hasType()) { visitAnnotatedAssignGetprop(t, assign, info.getType().evaluate(t.getScope()), object, property, rvalue); return; } // /** @enum ... */object.name = ...; if (info != null && info.hasEnumParameterType()) { checkEnumInitializer( t, rvalue, info.getEnumParameterType().evaluate(t.getScope())); return; } // object.prototype = ...

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>; if (property.equals("prototype")) { if (objectJsType instanceof FunctionType) { FunctionType functionType = (FunctionType) objectJsType; if (functionType.isConstructor()) { JSType rvalueType = rvalue.getJSType(); validator.expectObject(t, rvalue, rvalueType, OVERRIDING_PROTOTYPE_WITH_NON_OBJECT); } } else { // TODO(user): might want to flag that } return; } // object.prototype.property = ...; if (object.getType() == Token.GETPROP) { Node object2 = object.getFirstChild(); String property2 = NodeUtil.getStringValue(object.getLastChild()); if ("prototype".equals(property2)) { JSType jsType = object2.getJSType(); if (jsType instanceof FunctionType) { FunctionType functionType = (FunctionType) jsType; if (functionType.isConstructor() || functionType.isInterface()) { checkDeclaredPropertyInheritance( t, assign, functionType, property, info, getJSType(rvalue)); } } else { // TODO(user): might want to flag that } return; } } // object.property = ...; ObjectType type = ObjectType.cast( objectJsType.restrictByNotNullOrUndefined()); if (type != null) { if (type.hasProperty(property) && !type.isPropertyTypeInferred(property) && !propertyIsImplicitCast(type, property)) { validator.expectCanAssignToPropertyOf( t, assign, getJSType(rvalue), type.getPropertyType(property), object, property); } return; } } else if (lvalue.getType() == Token.NAME) { // variable with inferred type case JSType rvalueType = getJSType(assign.getLastChild()); Var var = t.getScope().getVar(lvalue.getString()); if (var != null) { if (var.isTypeInferred()) { return; } } } // fall through case JSType leftType = getJSType(lvalue); Node rightChild = assign.getLastChild(); JSType rightType = getJSType(rightChild);

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> if (validator.expectCanAssignTo( t, assign, rightType, leftType, "assignment")) { ensureTyped(t, assign, rightType); } else { ensureTyped(t, assign); } } /** * Returns true if any type in the chain has an implictCast annotation for * the given property. */ private boolean propertyIsImplicitCast(ObjectType type, String prop) { for (; type != null; type = type.getImplicitPrototype()) { JSDocInfo docInfo = type.getOwnPropertyJSDocInfo(prop); if (docInfo != null && docInfo.isImplicitCast()) { return true; } } return false; } /** * Given a constructor type and a property name, check that the property has * the JSDoc annotation @override iff the property is declared on a * superclass. Several checks regarding inheritance correctness are also * performed. */ private void checkDeclaredPropertyInheritance( NodeTraversal t, Node n, FunctionType ctorType, String propertyName, JSDocInfo info, JSType propertyType) { // TODO(user): We're not 100% confident that type-checking works, // so we return quietly if the unknown type is a superclass of this type. // Remove this check as we become more confident. We should flag a warning // when the unknown type is on the inheritance chain, as it is likely // because of a programmer error. if (ctorType.hasUnknownSupertype()) { return; } FunctionType superClass = ctorType.getSuperClassConstructor(); boolean superClassHasProperty = superClass != null && superClass.getPrototype().hasProperty(propertyName); boolean declaredOverride = info != null && info.isOverride(); boolean foundInterfaceProperty = false; if (ctorType.isConstructor()) { for (JSType implementedInterface : ctorType.getImplementedInterfaces()) { if (implementedInterface.isUnknownType()) { continue; } FunctionType interfaceType = implementedInterface.toObjectType().getConstructor(); boolean interfaceHasProperty = interfaceType.getPrototype().hasProperty(propertyName); foundInterfaceProperty = foundInterfaceProperty || interfaceHasProperty; if (reportMissingOverride.isOn() && !declaredOverride && interfaceHas

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Property) { // @override not present, but the property does override an interface // property compiler.report(JSError.make(t, n, reportMissingOverride, HIDDEN_INTERFACE_PROPERTY, propertyName, interfaceType.getTopMostDefiningType(propertyName).toString())); } if (!declaredOverride) { continue; } // @override is present and we have to check that it is ok if (interfaceHasProperty) { JSType interfacePropType = interfaceType.getPrototype().getPropertyType(propertyName); if (!propertyType.canAssignTo(interfacePropType)) { compiler.report(JSError.make(t, n, HIDDEN_INTERFACE_PROPERTY_MISMATCH, propertyName, interfaceType.getTopMostDefiningType(propertyName).toString(), interfacePropType.toString(), propertyType.toString())); } } } } if (!declaredOverride && !superClassHasProperty) { // nothing to do here, it's just a plain new property return; } JSType topInstanceType = superClassHasProperty ? superClass.getTopMostDefiningType(propertyName) : null; if (reportMissingOverride.isOn() && ctorType.isConstructor() && !declaredOverride && superClassHasProperty) { // @override not present, but the property does override a superclass // property compiler.report(JSError.make(t, n, reportMissingOverride, HIDDEN_SUPERCLASS_PROPERTY, propertyName, topInstanceType.toString())); } if (!declaredOverride) { // there's no @override to check return; } // @override is present and we have to check that it is ok if (superClassHasProperty) { // there is a superclass implementation JSType superClassPropType = superClass.getPrototype().getPropertyType(propertyName); if (!propertyType.canAssignTo(superClassPropType)) { compiler.report( JSError.make(t, n, HIDDEN_SUPERCLASS_PROPERTY_MISMATCH, propertyName, topInstanceType.toString(), superClassPropType.toString(), propertyType.toString())); } } else if (!foundInterfaceProperty) { // there is no superclass nor interface implementation compiler.report( JSError.make(t, n, UNKNOWN_OVERRIDE

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>, propertyName, ctorType.getInstanceType().toString())); } } /** * Visits an ASSIGN node for cases such as * <pre> * interface.property2.property = ...; * </pre> */ private void visitInterfaceGetprop(NodeTraversal t, Node assign, Node object, String property, Node lvalue, Node rvalue) { JSType rvalueType = getJSType(rvalue); String abstractMethodName = compiler.getCodingConvention().getAbstractMethodName(); if (!rvalueType.isOrdinaryFunction() && !(rvalue.isQualifiedName() && rvalue.getQualifiedName().equals(abstractMethodName))) { compiler.report(JSError.make(t, object, INTERFACE_FUNCTION_MEMBERS_ONLY, abstractMethodName)); } if (assign.getLastChild().getType() == Token.FUNCTION && !NodeUtil.isEmptyBlock(assign.getLastChild().getLastChild())) { compiler.report(JSError.make(t, object, INTERFACE_FUNCTION_NOT_EMPTY, abstractMethodName)); } } /** * Visits an ASSIGN node for cases such as * <pre> * object.property = ...; * </pre> * that have an {@code @type} annotation. */ private void visitAnnotatedAssignGetprop(NodeTraversal t, Node assign, JSType type, Node object, String property, Node rvalue) { // verifying that the rvalue has the correct type validator.expectCanAssignToPropertyOf(t, assign, getJSType(rvalue), type, object, property); } /** * Visits a NAME node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. * @param parent The parent of the node n. * @return whether the node is typeable or not */ boolean visitName(NodeTraversal t, Node n, Node parent) { // At this stage, we need to determine whether this is a leaf // node in an expression (which therefore needs to have a type // assigned for it) versus some other decorative node that we // can safely ignore.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> Function names, arguments (children of LP nodes) and // variable declarations are ignored. // TODO(user): remove this short-circuiting in favor of a // pre order traversal of the FUNCTION, CATCH, LP and VAR nodes. int parentNodeType = parent.getType(); if (parentNodeType == Token.FUNCTION || parentNodeType == Token.CATCH || parentNodeType == Token.LP || parentNodeType == Token.VAR) { return false; } JSType type = n.getJSType(); if (type == null) { type = getNativeType(UNKNOWN_TYPE); Var var = t.getScope().getVar(n.getString()); if (var != null) { JSType varType = var.getType(); if (varType != null) { type = varType; } } } ensureTyped(t, n, type); return true; } /** * Visits a GETPROP node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. * @param parent The parent of <code>n</code> */ private void visitGetProp(NodeTraversal t, Node n, Node parent) { // GETPROP nodes have an assigned type on their node by the scope creator // if this is an enum declaration. The only namespaced enum declarations // that we allow are of the form object.name = ...; if (n.getJSType() != null && parent.getType() == Token.ASSIGN) { return; } // obj.prop or obj.method() // Lots of types can appear on the left, a call to a void function can // never be on the left. getPropertyType will decide what is acceptable // and what isn't. Node property = n.getLastChild(); Node objNode = n.getFirstChild(); JSType childType = getJSType(objNode); // TODO(user): remove in favor of flagging every property access on // non-object. if (!validator.expectNotVoid(t, n, childType, "undefined has no properties", getNativeType(OBJECT_TYPE))) { ensureTyped(t, n);

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> return; } checkPropertyAccess(childType, property.getString(), t, n); ensureTyped(t, n); } /** * Make sure that the access of this property is ok. */ private void checkPropertyAccess(JSType childType, String propName, NodeTraversal t, Node n) { ObjectType objectType = childType.dereference(); if (objectType != null) { JSType propType = getJSType(n); if ((!objectType.hasProperty(propName) || objectType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) && propType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) { if (objectType instanceof EnumType) { t.report(n, INEXISTENT_ENUM_ELEMENT, propName); } else if (!objectType.isEmptyType() && reportMissingProperties && !isPropertyTest(n)) { if (!typeRegistry.canPropertyBeDefined(objectType, propName)) { t.report(n, INEXISTENT_PROPERTY, propName, validator.getReadableJSTypeName(n.getFirstChild(), true)); } } } } else { // TODO(nicksantos): might want to flag the access on a non object when // it's impossible to get a property from this type. } } /** * Determines whether this node is testing for the existence of a property. * If true, we will not emit warnings about a missing property. * * @param getProp The GETPROP being tested. */ private boolean isPropertyTest(Node getProp) { Node parent = getProp.getParent(); switch (parent.getType()) { case Token.CALL: return parent.getFirstChild() != getProp && compiler.getCodingConvention().isPropertyTestFunction(parent); case Token.IF: case Token.WHILE: case Token.DO: case Token.FOR: return NodeUtil.getConditionExpression(parent) == getProp; case Token.INSTANCEOF: case Token.TYPEOF: return true; case Token.AND: case Token.HOOK: return parent.getFirstChild() == getProp; } return false; } /** * Visits a GET

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>ELEM node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. */ private void visitGetElem(NodeTraversal t, Node n) { Node left = n.getFirstChild(); Node right = n.getLastChild(); validator.expectIndexMatch(t, n, getJSType(left), getJSType(right)); ensureTyped(t, n); } /** * Visits a VAR node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. */ private void visitVar(NodeTraversal t, Node n) { // TODO(nicksantos): Fix this so that the doc info always shows up // on the NAME node. We probably want to wait for the parser // merge to fix this. JSDocInfo varInfo = n.hasOneChild() ? n.getJSDocInfo() : null; for (Node name : n.children()) { Node value = name.getFirstChild(); // A null var would indicate a bug in the scope creation logic. Var var = t.getScope().getVar(name.getString()); if (value != null) { JSType valueType = getJSType(value); JSType nameType = var.getType(); nameType = (nameType == null) ? getNativeType(UNKNOWN_TYPE) : nameType; JSDocInfo info = name.getJSDocInfo(); if (info == null) { info = varInfo; } if (info != null && info.hasEnumParameterType()) { // var.getType() can never be null, this would indicate a bug in the // scope creation logic. checkEnumInitializer( t, value, info.getEnumParameterType().evaluate(t.getScope())); } else if (var.isTypeInferred()) { ensureTyped(t, name, valueType); } else { validator.expectCanAssignTo( t, value, valueType, nameType, "initializing variable"); } } } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> /** * Visits a NEW node. */ private void visitNew(NodeTraversal t, Node n) { Node constructor = n.getFirstChild(); FunctionType type = getFunctionType(constructor); if (type != null && type.isConstructor()) { visitParameterList(t, n, type); ensureTyped(t, n, type.getInstanceType()); } else { // TODO(user): add support for namespaced objects. if (constructor.getType() != Token.GETPROP) { // TODO(user): make the constructor node have lineno/charno // and use constructor for a more precise error indication. // It seems that GETPROP nodes are missing this information. Node line; if (constructor.getLineno() < 0 || constructor.getCharno() < 0) { line = n; } else { line = constructor; } t.report(line, NOT_A_CONSTRUCTOR); } ensureTyped(t, n); } } /** * Visits a {@link Token#FUNCTION} node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. */ private void visitFunction(NodeTraversal t, Node n) { JSDocInfo info = n.getJSDocInfo(); FunctionType functionType = (FunctionType) n.getJSType(); String functionPrivateName = n.getFirstChild().getString(); if (functionType.isInterface() || functionType.isConstructor()) { FunctionType baseConstructor = functionType. getPrototype().getImplicitPrototype().getConstructor(); if (baseConstructor != null && baseConstructor != getNativeType(OBJECT_FUNCTION_TYPE) && (baseConstructor.isConstructor() && functionType.isInterface() || baseConstructor.isInterface() && functionType.isConstructor())) { compiler.report( JSError.make(t, n, CONFLICTING_EXTENDED_TYPE, functionPrivateName)); } for (JSType baseInterface : functionType.getImplementedInterfaces()) { boolean badImplementedType = false; ObjectType baseInterfaceObj = ObjectType.cast(baseInterface); if (baseInterfaceObj

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> != null) { FunctionType interfaceConstructor = baseInterfaceObj.getConstructor(); if (interfaceConstructor != null && !interfaceConstructor.isInterface()) { badImplementedType = true; } } else { badImplementedType = true; } if (badImplementedType) { t.report(n, BAD_IMPLEMENTED_TYPE, functionPrivateName); } } if (functionType.isConstructor()) { validator.expectAllInterfacePropertiesImplemented(functionType); } } } /** * Visits a CALL node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. */ private void visitCall(NodeTraversal t, Node n) { Node child = n.getFirstChild(); JSType childType = getJSType(child).restrictByNotNullOrUndefined(); if (!childType.canBeCalled()) { t.report(n, NOT_CALLABLE, childType.toString()); ensureTyped(t, n); return; } // A couple of types can be called as if they were functions. // If it is a function type, then validate parameters. if (childType instanceof FunctionType) { FunctionType functionType = (FunctionType) childType; // Non-native constructors should never be called directly. if (functionType.isConstructor() && !functionType.isNativeObjectType()) { t.report(n, CONSTRUCTOR_NOT_CALLABLE, childType.toString()); } visitParameterList(t, n, functionType); ensureTyped(t, n, functionType.getReturnType()); } else { ensureTyped(t, n); } // TODO: Add something to check for calls of RegExp objects, which is not // supported by IE. Either say something about the return type or warn // about the non-portability of the call or both. } /** * Visits the parameters of a CALL or a NEW node. */ private void visitParameterList(NodeTraversal t, Node call, FunctionType functionType) { Iterator<Node> arguments = call.children().iterator(); arguments.next(); // skip the function name

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> Iterator<Node> parameters = functionType.getParameters().iterator(); int ordinal = 0; while (arguments.hasNext() && parameters.hasNext()) { Node parameter = parameters.next(); Node argument = arguments.next(); ordinal++; validator.expectArgumentMatchesParameter(t, argument, getJSType(argument), getJSType(parameter), call, ordinal); } int numArgs = call.getChildCount() - 1; int minArgs = functionType.getMinArguments(); int maxArgs = functionType.getMaxArguments(); if (minArgs > numArgs || maxArgs < numArgs) { t.getCompiler().report( JSError.make(t, call, WRONG_ARGUMENT_COUNT, validator.getReadableJSTypeName(call.getFirstChild(), false), String.valueOf(numArgs), String.valueOf(minArgs), maxArgs != Integer.MAX_VALUE ? " and no more than " + maxArgs + " argument(s)" : "")); } } /** * Visits a RETURN node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. */ private void visitReturn(NodeTraversal t, Node n) { Node function = t.getEnclosingFunction(); // This is a misplaced return, but the real JS will fail to compile, // so let it go. if (function == null) { return; } JSType jsType = getJSType(function); if (jsType instanceof FunctionType) { FunctionType functionType = (FunctionType) jsType; JSType returnType = functionType.getReturnType(); // if no return type is specified, undefined must be returned // (it's a void function) if (returnType == null) { returnType = getNativeType(VOID_TYPE); } // fetching the returned value's type Node valueNode = n.getFirstChild(); JSType actualReturnType; if (valueNode == null) { actualReturnType = getNativeType(VOID_TYPE); valueNode = n; } else { actualReturnType = getJSType(valueNode); } // verifying validator.expectCanAssignTo

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>(t, valueNode, actualReturnType, returnType, "inconsistent return type"); } } /** * This function unifies the type checking involved in the core binary * operators and the corresponding assignment operators. The representation * used internally is such that common code can handle both kinds of * operators easily. * * @param op The operator. * @param t The traversal object, needed to report errors. * @param n The node being checked. */ private void visitBinaryOperator(int op, NodeTraversal t, Node n) { Node left = n.getFirstChild(); JSType leftType = getJSType(left); Node right = n.getLastChild(); JSType rightType = getJSType(right); switch (op) { case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.LSH: case Token.RSH: case Token.ASSIGN_URSH: case Token.URSH: if (!leftType.matchesInt32Context()) { t.report(left, BIT_OPERATION, NodeUtil.opToStr(n.getType()), leftType.toString()); } if (!rightType.matchesUint32Context()) { t.report(right, BIT_OPERATION, NodeUtil.opToStr(n.getType()), rightType.toString()); } break; case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: case Token.ASSIGN_MUL: case Token.ASSIGN_SUB: case Token.DIV: case Token.MOD: case Token.MUL: case Token.SUB: validator.expectNumber(t, left, leftType, "left operand"); validator.expectNumber(t, right, rightType, "right operand"); break; case Token.ASSIGN_BITAND: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITOR: case Token.BITAND: case Token.BITXOR: case Token.BITOR: validator.expectBitwiseable(t, left, leftType, "bad left operand to bitwise operator"); validator.expectBitwiseable(t, right, rightType, "bad right operand to bitwise operator"); break; case Token.ASSIGN_ADD

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>: case Token.ADD: break; default: t.report(n, UNEXPECTED_TOKEN, Node.tokenToName(op)); } ensureTyped(t, n); } /** * <p>Checks the initializer of an enum. An enum can be initialized with an * object literal whose values must be subtypes of the declared enum element * type, or by copying another enum.</p> * * <p>In the case of an enum copy, we verify that the enum element type of the * enum used for initialization is a subtype of the enum element type of * the enum the value is being copied in.</p> * * <p>Examples:</p> * <pre>var myEnum = {FOO: ..., BAR: ...}; * var myEnum = myOtherEnum;</pre> * * @param value the value used for initialization of the enum * @param primitiveType The type of each element of the enum. */ private void checkEnumInitializer( NodeTraversal t, Node value, JSType primitiveType) { if (value.getType() == Token.OBJECTLIT) { // re-using value as the value of the object literal and advancing twice value = value.getFirstChild(); value = (value == null) ? null : value.getNext(); while (value != null) { // the value's type must be assignable to the enum's primitive type validator.expectCanAssignTo(t, value, getJSType(value), primitiveType, "element type must match enum's type"); // advancing twice value = value.getNext(); value = (value == null) ? null : value.getNext(); } } else if (value.getJSType() instanceof EnumType) { // TODO(user): Remove the instanceof check in favor // of a type.isEnumType() predicate. Currently, not all enum types are // implemented by the EnumClass, e.g. the unknown type and the any // type. The types need to be defined by interfaces such that an // implementation can implement multiple types interface. EnumType valueEnumType = (EnumType) value.getJSType(); JSType valueEnumPrimitiveType = valueEnumType.getElementsType().getPrimitiveType(); validator.expectCanAssignTo(

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>t, value, valueEnumPrimitiveType, primitiveType, "incompatible enum element types"); } else { // The error condition is handled in TypedScopeCreator. } } /** * This predicate is used to determine if the node represents an expression * that is a Reference according to JavaScript definitions. * * @param n The node being checked. * @return true if the sub-tree n is a reference, false otherwise. */ private static boolean isReference(Node n) { switch (n.getType()) { case Token.GETELEM: case Token.GETPROP: case Token.NAME: return true; default: return false; } } /** * This method gets the JSType from the Node argument and verifies that it is * present. */ private JSType getJSType(Node n) { JSType jsType = n.getJSType(); if (jsType == null) { // TODO(nicksantos): This branch indicates a compiler bug, not worthy of // halting the compilation but we should log this and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } /** * Gets the type of the node or {@code null} if the node's type is not a * function. */ private FunctionType getFunctionType(Node n) { JSType type = getJSType(n).restrictByNotNullOrUndefined(); if (type.isUnknownType()) { return typeRegistry.getNativeFunctionType(U2U_CONSTRUCTOR_TYPE); } else if (type instanceof FunctionType) { return (FunctionType) type; } else { return null; } } // TODO(nicksantos): TypeCheck should never be attaching types to nodes. // All types should be attached by TypeInference. This is not true today // for legacy reasons. There are a number of places where TypeInference // doesn't attach a type, as a signal to TypeCheck that it needs to check // that node's type. /** * Ensure that the given node has a type. If it does not have one, *

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> attach the UNKNOWN_TYPE. */ private void ensureTyped(NodeTraversal t, Node n) { ensureTyped(t, n, getNativeType(UNKNOWN_TYPE)); } private void ensureTyped(NodeTraversal t, Node n, JSTypeNative type) { ensureTyped(t, n, getNativeType(type)); } /** * Enforces type casts, and ensures the node is typed. * * A cast in the way that we use it in JSDoc annotations never * alters the generated code and therefore never can induce any runtime * operation. What this means is that a 'cast' is really just a compile * time constraint on the underlying value. In the future, we may add * support for run-time casts for compiled tests. * * To ensure some shred of sanity, we enforce the notion that the * type you are casting to may only meaningfully be a narrower type * than the underlying declared type. We also invalidate optimizations * on bad type casts. * * @param t The traversal object needed to report errors. * @param n The node getting a type assigned to it. * @param type The type to be assigned. */ private void ensureTyped(NodeTraversal t, Node n, JSType type) { // Make sure FUNCTION nodes always get function type. Preconditions.checkState(n.getType() != Token.FUNCTION || type instanceof FunctionType || type.isUnknownType()); JSDocInfo info = n.getJSDocInfo(); if (info != null) { if (info.hasType()) { JSType infoType = info.getType().evaluate(t.getScope()); validator.expectCanCast(t, n, infoType, type); type = infoType; } if (info.isImplicitCast() && !inExterns) { String propName = n.getType() == Token.GETPROP ? n.getLastChild().getString() : "(missing)"; compiler.report( JSError.make(t, n, ILLEGAL_IMPLICIT_CAST, propName)); } } if (n.getJSType() == null) { n.setJSType(type); } } /** * Returns the percentage of

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> + "\nCached : {0}\nActual : {1}"); static final DiagnosticType SCOPE_MISMATCH = DiagnosticType.error( "JSC_SCOPE_MISMATCH", "Scope roots used with the symbol table do not match." + "\nExpected : {0}\nActual : {1}"); private final AbstractCompiler compiler; private final ScopeCreator scopeCreator; // Mutex so that the symbol table may only be acquired by one pass // at a time. private boolean locked = false; // Memoized data with the pass that has currently acquired the // symbol table. private MemoizedData cache = null; SymbolTable(AbstractCompiler compiler) { this.compiler = compiler; compiler.addChangeHandler(this); scopeCreator = new SyntacticScopeCreator(compiler); } synchronized void acquire() { Preconditions.checkState(!locked, "SymbolTable already acquired"); locked = true; } synchronized void release() { Preconditions.checkState(locked, "SymbolTable already released"); locked = false; } /** * Returns the scope at the given node. */ @Override public Scope createScope(Node n, Scope parent) { // We may only ask for local blocks and the global (all scripts) block. Preconditions.checkArgument( (n.getType() == Token.BLOCK && n.getParent() == null) || n.getType() == Token.FUNCTION, "May only create scopes for the global node and functions"); ensureCacheInitialized(); if (!cache.scopes.containsKey(n)) { cache.scopes.put(n, scopeCreator.createScope(n, parent)); } return cache.scopes.get(n); } /** * Ensure that the memoization data structures have been initialized. */ private void ensureCacheInitialized() { Preconditions.checkState(locked, "Unacquired symbol table"); if (cache == null) { cache = new MemoizedData(); } } /** * If the AST changes, and the symbol table has not been acquired, then * all of our memoized data structures become stale. So delete them. */ @Override public void reportChange() { if (!locked) { cache = null; } } /** * All the

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> data structures cached by this table. */ private static class MemoizedData { private Map<Node, Scope> scopes = Maps.newHashMap(); } //---------------------------------------------------------------------------- // Verification of consistency. Only for tests. /** * Check that this symbol table has been kept up to date. Compiler warnings * will be emitted if anything is wrong. * @param expectedRoot The root of the expected AST. * @param actualRoot The root of the actual AST used with this symbol table. */ void verify(Node expectedRoot, Node actualRoot) { VerifyingCallback callback = new VerifyingCallback( expectedRoot, actualRoot); callback.verify(); } /** * A callback that traverses an AST root and builds all the * secondary data structures for it. */ private class VerifyingCallback implements ScopedCallback { private final List<Scope> expectedScopes = Lists.newArrayList(); private final List<Scope> actualScopes = Lists.newArrayList(); private boolean collectingExpected = true; private final Node actualRoot; private final Node expectedRoot; private VerifyingCallback(Node expectedRoot, Node actualRoot) { this.actualRoot = actualRoot; this.expectedRoot = expectedRoot; } @Override public boolean shouldTraverse( NodeTraversal nodeTraversal, Node n, Node parent) { return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) {} @Override public void enterScope(NodeTraversal t) {} @Override public void exitScope(NodeTraversal t) { if (collectingExpected) { expectedScopes.add(t.getScope()); } else { actualScopes.add(t.getScope()); } } private void verify() { if (cache == null) { // The symbol table was never used, so no need to check anything. return; } if (!cache.scopes.isEmpty()) { verifyScopes(); } } private void verifyScopes() { collectingExpected = true; NodeTraversal.traverse(compiler, expectedRoot, this); collectingExpected = false; (new NodeTraversal(compiler, this, SymbolTable.this)) .traverse(actualRoot); // This must be true unless something went horribly, horribly wrong.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>) { registry.identifyEnumName( node.getFirstChild().getQualifiedName()); } } } private int position2charno(int position) { int lineIndex = sourceString.lastIndexOf('\n', position); if (lineIndex == -1) { return position; } else { // Subtract one for initial position being 0. return position - lineIndex - 1; } } private Node justTransform(AstNode node) { return transformDispatcher.process(node); } private class TransformDispatcher extends TypeSafeDispatcher<Node> { private Node processGeneric( com.google.javascript.jscomp.mozilla.rhino.Node n) { Node node = new Node(transformTokenType(n.getType())); for (com.google.javascript.jscomp.mozilla.rhino.Node child : n) { node.addChildToBack(transform((AstNode)child)); } return node; } /** * Transforms the given node and then sets its type to Token.STRING if it * was Token.NAME. If its type was already Token.STRING, then quotes it. * Used for properties, as the old AST uses String tokens, while the new one * uses Name tokens for unquoted strings. For example, in * var o = {'a' : 1, b: 2}; * the string 'a' is quoted, while the name b is turned into a string, but * unquoted. */ private Node transformAsString(AstNode n) { Node ret = transform(n); if (ret.getType() == Token.STRING) { ret.putBooleanProp(Node.QUOTED_PROP, true); } else if (ret.getType() == Token.NAME) { ret.setType(Token.STRING); } return ret; } @Override Node processArrayLiteral(ArrayLiteral literalNode) { if (literalNode.isDestructuring()) { reportDestructuringAssign(literalNode); } Node node = new Node(Token.ARRAYLIT); int skipCount = 0; for (AstNode child : literalNode.getElements()) { Node c = transform(child); if (c.getType() == Token.EMPTY) { skipCount++; }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> node.addChildToBack(c); } if (skipCount > 0) { int[] skipIndexes = new int[skipCount]; int i = 0; int j = 0; for (Node child : node.children()) { if (child.getType() == Token.EMPTY) { node.removeChild(child); skipIndexes[j] = i; j++; } i++; } node.putProp(Node.SKIP_INDEXES_PROP, skipIndexes); } return node; } @Override Node processAssignment(Assignment assignmentNode) { return processInfixExpression(assignmentNode); } @Override Node processAstRoot(AstRoot rootNode) { Node node = new ScriptOrFnNode(Token.SCRIPT); for (com.google.javascript.jscomp.mozilla.rhino.Node child : rootNode) { node.addChildToBack(transform((AstNode)child)); } parseDirectives(node); return node; } /** * Parse the directives, encode them in the AST, and remove their nodes. * * For information on ES5 directives, see section 14.1 of * Ecma-262, Edition 5. * * It would be nice if Rhino would eventually take care of this for * us, but right now their directive-processing is a one-off. */ private void parseDirectives(Node node) { // Remove all the directives, and encode them in the AST. Set<String> directives = null; while (isDirective(node.getFirstChild())) { String directive = node.removeFirstChild().getFirstChild().getString(); if (directives == null) { directives = Sets.newHashSet(directive); } else { directives.add(directive); } } if (directives != null) { node.setDirectives(directives); } } private boolean isDirective(Node n) { if (n == null) return false; int nType = n.getType(); return (nType == Token.EXPR_RESULT || nType == Token.EXPR_VOID) && n.getFirstChild().getType() == Token.STRING && ALLOWED_DIRECTIVES.contains(n.getFirstChild

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>(Token.EMPTY); return node; } @Override Node processExpressionStatement(ExpressionStatement statementNode) { Node node = new Node(transformTokenType(statementNode.getType())); node.addChildToBack(transform(statementNode.getExpression())); return node; } @Override Node processForInLoop(ForInLoop loopNode) { return new Node( Token.FOR, transform(loopNode.getIterator()), transform(loopNode.getIteratedObject()), transform(loopNode.getBody())); } @Override Node processForLoop(ForLoop loopNode) { Node node = new Node( Token.FOR, transform(loopNode.getInitializer()), transform(loopNode.getCondition()), transform(loopNode.getIncrement())); node.addChildToBack(transform(loopNode.getBody())); return node; } @Override Node processFunctionCall(FunctionCall callNode) { Node node = new Node(transformTokenType(callNode.getType()), transform(callNode.getTarget())); for (AstNode child : callNode.getArguments()) { node.addChildToBack(transform(child)); } int leftParamPos = callNode.getAbsolutePosition() + callNode.getLp(); node.setLineno(callNode.getLineno()); node.setCharno(position2charno(leftParamPos)); return node; } @Override Node processFunctionNode(FunctionNode functionNode) { Name name = functionNode.getFunctionName(); Boolean isUnnamedFunction = false; if (name == null) { name = new Name(); name.setIdentifier(""); isUnnamedFunction = true; } Node node = new com.google.javascript.rhino.FunctionNode( name.getIdentifier()); node.putProp(Node.SOURCENAME_PROP, functionNode.getSourceName()); Node newName = transform(name); if (isUnnamedFunction) { // Old Rhino tagged the empty name node with the line number of the // declaration. newName.setLineno(functionNode.getLineno()); // TODO(user) Mark line number of paren correctly. // Same problem as below - the left paren might not be on the // same line as the function keyword.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> int lpColumn = functionNode.getAbsolutePosition() + functionNode.getLp(); newName.setCharno(position2charno(lpColumn)); } node.addChildToBack(newName); Node lp = new Node(Token.LP); // The left paren's complicated because it's not represented by an // AstNode, so there's nothing that has the actual line number that it // appeared on. We know the paren has to appear on the same line as the // function name (or else a semicolon will be inserted.) If there's no // function name, assume the paren was on the same line as the function. // TODO(user): Mark line number of paren correctly. Name fnName = functionNode.getFunctionName(); if (fnName != null) { lp.setLineno(fnName.getLineno()); } else { lp.setLineno(functionNode.getLineno()); } int lparenCharno = functionNode.getLp() + functionNode.getAbsolutePosition(); lp.setCharno(position2charno(lparenCharno)); for (AstNode param : functionNode.getParams()) { lp.addChildToBack(transform(param)); } node.addChildToBack(lp); Node bodyNode = transform(functionNode.getBody()); parseDirectives(bodyNode); node.addChildToBack(bodyNode); return node; } @Override Node processIfStatement(IfStatement statementNode) { Node node = new Node(Token.IF); node.addChildToBack(transform(statementNode.getCondition())); node.addChildToBack(transform(statementNode.getThenPart())); if (statementNode.getElsePart() != null) { node.addChildToBack(transform(statementNode.getElsePart())); } return node; } @Override Node processInfixExpression(InfixExpression exprNode) { Node n = new Node( transformTokenType(exprNode.getType()), transform(exprNode.getLeft()), transform(exprNode.getRight())); // Set the line number here so we can fine-tune it in ways transform // doesn't do. n.setLineno(exprNode.getLineno());

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> // Position in new ASTNode is to start of expression, but old-fashioned // line numbers from Node reference the operator token. Add the offset // to the operator to get the correct character number. n.setCharno(position2charno(exprNode.getAbsolutePosition() + exprNode.getOperatorPosition())); return n; } @Override Node processKeywordLiteral(KeywordLiteral literalNode) { return new Node(transformTokenType(literalNode.getType())); } @Override Node processLabel(Label labelNode) { return Node.newString(Token.NAME, labelNode.getName()); } @Override Node processLabeledStatement(LabeledStatement statementNode) { Node node = new Node(Token.LABEL); Node prev = null; Node cur = node; for (Label label : statementNode.getLabels()) { if (prev != null) { prev.addChildToBack(cur); } cur.addChildToBack(transform(label)); prev = cur; cur = new Node(Token.LABEL); } prev.addChildToBack(transform(statementNode.getStatement())); return node; } @Override Node processName(Name nameNode) { return Node.newString(Token.NAME, nameNode.getIdentifier()); } @Override Node processNewExpression(NewExpression exprNode) { return processFunctionCall(exprNode); } @Override Node processNumberLiteral(NumberLiteral literalNode) { Node newNode = Node.newNumber(literalNode.getNumber()); return newNode; } @Override Node processObjectLiteral(ObjectLiteral literalNode) { if (literalNode.isDestructuring()) { reportDestructuringAssign(literalNode); } Node node = new Node(Token.OBJECTLIT); for (ObjectProperty el : literalNode.getElements()) { node.addChildToBack(transformAsString(el.getLeft())); node.addChildToBack(transform(el.getRight())); } return node; } @Override Node processObjectProperty(ObjectProperty propertyNode) { return processInfixExpression(propertyNode); } @Override Node processParenthesizedExpression(ParenthesizedExpression exprNode) { Node node = transform(exprNode.getExpression()); node

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>.putProp(Node.PARENTHESIZED_PROP, Boolean.TRUE); return node; } @Override Node processPropertyGet(PropertyGet getNode) { return new Node( Token.GETPROP, transform(getNode.getTarget()), transformAsString(getNode.getProperty())); } @Override Node processRegExpLiteral(RegExpLiteral literalNode) { Node literalStringNode = Node.newString(literalNode.getValue()); // assume it's on the same line. literalStringNode.setLineno(literalNode.getLineno()); Node node = new Node(Token.REGEXP, literalStringNode); String flags = literalNode.getFlags(); if (flags != null && !flags.isEmpty()) { Node flagsNode = Node.newString(flags); // Assume the flags are on the same line as the literal node. flagsNode.setLineno(literalNode.getLineno()); node.addChildToBack(flagsNode); } return node; } @Override Node processReturnStatement(ReturnStatement statementNode) { Node node = new Node(Token.RETURN); if (statementNode.getReturnValue() != null) { node.addChildToBack(transform(statementNode.getReturnValue())); } return node; } @Override Node processScope(Scope scopeNode) { return processGeneric(scopeNode); } @Override Node processStringLiteral(StringLiteral literalNode) { Node n = Node.newString(literalNode.getValue()); return n; } @Override Node processSwitchCase(SwitchCase caseNode) { Node node; if (caseNode.isDefault()) { node = new Node(Token.DEFAULT); } else { AstNode expr = caseNode.getExpression(); node = new Node(Token.CASE, transform(expr)); } Node block = new Node(Token.BLOCK); block.putBooleanProp(Node.SYNTHETIC_BLOCK_PROP, true); block.setLineno(caseNode.getLineno()); block.setCharno(position2charno(caseNode.getAbsolutePosition())); if (caseNode.getStatements() != null) { for (AstNode child : caseNode.getStatements()) { block.addChildToBack(transform(

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>.append(':'); b.append(error.lineNumber); } b.append(": "); } b.append(getLevelName(warning ? CheckLevel.WARNING : CheckLevel.ERROR)); b.append(" - "); b.append(error.description); b.append('\n'); if (sourceExcerpt != null) { b.append(sourceExcerpt); b.append('\n'); int charno = error.getCharno(); // padding equal to the excerpt and arrow at the end if (excerpt.equals(LINE) && 0 <= charno && charno < sourceExcerpt.length()) { for (int i = 0; i < charno; i++) { char c = sourceExcerpt.charAt(i); if (Character.isWhitespace(c)) { b.append(c); } else { b.append(' '); } } b.append("^\n"); } } return b.toString(); } /** * Formats a region by appending line numbers in front, e.g. * <pre> 9| if (foo) { * 10| alert('bar'); * 11| }</pre> * and return line excerpt without any modification. */ static class LineNumberingFormatter implements ExcerptFormatter { public String formatLine(String line, int lineNumber) { return line; } public String formatRegion(Region region) { if (region == null) { return null; } String code = region.getSourceExcerpt(); if (code.length() == 0) { return null; } // max length of the number display int numberLength = Integer.toString(region.getEndingLineNumber()) .length(); // formatting StringBuilder builder = new StringBuilder(code.length() * 2); int start = 0; int end = code.indexOf('\n', start); int lineNumber = region.getBeginningLineNumber(); while (start >= 0) { // line extraction String line; if (end < 0) { line = code.substring(start); if (line.length() == 0) { return builder.substring(0, builder.length() -

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>/* * Copyright 2005 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Charsets; import com.google.common.collect.Maps; import com.google.common.io.ByteStreams; import com.google.common.io.CharStreams; import com.google.common.io.Files; import java.io.*; import java.text.*; import java.util.*; /** * Stores the mapping from original variable name to new variable names. * @see RenameVars */ public class VariableMap { /** Maps original source name to new name */ private final Map<String, String> map; /** Maps new name to source name, lazily initialized */ private Map<String, String> reverseMap = null; private static final char SEPARATOR = ':'; VariableMap(Map<String, String> map) { this.map = Collections.unmodifiableMap(map); } /** * Given an original variable name, look up new name, may return null * if it's not found. */ public String lookupNewName(String sourceName) { return map.get(sourceName); } /** * Given a new variable name, lookup the source name, may return null * if it's not found. */ public String lookupSourceName(String newName) { if (reverseMap == null) { initReverseMap(); } return reverseMap.get(newName); } /** * Initializes the reverse map. */ private synchronized void initReverseMap() { if (reverseMap == null) { Map<String, String> rm =

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>BLOCK); externsRoot.setIsSyntheticBlock(true); for (CompilerInput input : externs_) { Node n = input.getAstRoot(this); if (hasErrors()) { return null; } externsRoot.addChildToBack(n); } for (CompilerInput input : inputs_) { Node n = input.getAstRoot(this); if (hasErrors()) { return null; } // Inputs can have a null AST during initial parse. if (n == null) { continue; } if (devMode) { runSanityCheck(); if (hasErrors()) { return null; } } if (options_.sourceMapOutputPath != null || options_.nameReferenceReportPath != null) { // Annotate the nodes in the tree with information from the // input file. This information is used to construct the SourceMap. SourceInformationAnnotator sia = new SourceInformationAnnotator(input.getName()); NodeTraversal.traverse(this, n, sia); } jsRoot.addChildToBack(n); } externAndJsRoot = new Node(Token.BLOCK, externsRoot, jsRoot); externAndJsRoot.setIsSyntheticBlock(true); return externAndJsRoot; } finally { stopTracer(tracer, "parseInputs"); } } public Node parse(JSSourceFile file) { addToDebugLog("Parsing: " + file.getName()); return new JsAst(file).getAstRoot(this); } @Override Node parseSyntheticCode(String js) { CompilerInput input = new CompilerInput( JSSourceFile.fromCode(" [synthetic] ", js)); inputsByName_.put(input.getName(), input); return input.getAstRoot(this); } @Override Node parseSyntheticCode(String fileName, String js) { return parse(JSSourceFile.fromCode(fileName, js)); } Node parseTestCode(String js) { CompilerInput input = new CompilerInput( JSSourceFile.fromCode(" [testcode] ", js)); if (inputsByName_ == null) { inputsByName_ = Maps.newHashMap(); } inputsByName_.put(input

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> Preconditions.checkState(sourceName != null); Preconditions.checkState(!sourceName.isEmpty()); delimiter = delimiter.replaceAll("%name%", sourceName) .replaceAll("%num%", String.valueOf(inputSeqNum)); cb.append(delimiter) .append("\n"); } if (root.getJSDocInfo() != null && root.getJSDocInfo().getLicense() != null) { cb.append("/*\n") .append(root.getJSDocInfo().getLicense()) .append("*/\n"); } // If there is a valid source map, then indicate to it that the current // root node's mappings are offset by the given string builder buffer. if (options_.sourceMapOutputPath != null) { sourceMap_.setStartingPosition( cb.getLineIndex(), cb.getColumnIndex()); } String code = toSource(root); if (!code.isEmpty()) { cb.append(code); if (!code.endsWith(";")) { cb.append(";"); } } return null; } }); } /** * Generates JavaScript source code for an AST. */ @Override String toSource(Node n) { CodePrinter.Builder builder = new CodePrinter.Builder(n); builder.setPrettyPrint(options_.prettyPrint); builder.setLineBreak(options_.lineBreak); builder.setSourceMap(sourceMap_); builder.setOutputCharset(options_.outputCharset); return builder.build(); } /** * Stores a buffer of text to which more can be appended. This is just like a * StringBuilder except that we also track the number of lines. */ public static class CodeBuilder { private final StringBuilder sb = new StringBuilder(); private int lineCount = 0; /** Removes all text, but leaves the line count unchanged. */ void reset() { sb.setLength(0); } /** Appends the given string to the text buffer. */ CodeBuilder append(String str) { sb.append(str); // Move the line count to the end of the new text. int index = -1; while ((index = str.indexOf('\n', index + 1)) >= 0) { ++lineCount; } return

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> this; } /** Returns all text in the text buffer. */ @Override public String toString() { return sb.toString(); } /** Returns the length of the text buffer. */ public int getLength() { return sb.length(); } /** Returns the (zero-based) index of the last line in the text buffer. */ int getLineIndex() { return lineCount; } /** Returns the (zero-based) index of the last column in the text buffer. */ int getColumnIndex() { int index = sb.lastIndexOf("\n"); return (index >= 0) ? sb.length() - (index + 1) : sb.length(); } /** Determines whether the text ends with the given suffix. */ boolean endsWith(String suffix) { return (sb.length() > suffix.length()) && suffix.equals(sb.substring(sb.length() - suffix.length())); } } //------------------------------------------------------------------------ // Optimizations //------------------------------------------------------------------------ public void optimize() { PhaseOptimizer phaseOptimizer = new PhaseOptimizer(this, tracker); if (options_.devMode == DevMode.EVERY_PASS) { phaseOptimizer.setSanityCheck(sanityCheck); } phaseOptimizer.consume(getPassConfig().getOptimizations()); phaseOptimizer.process(externsRoot, jsRoot); if (hasErrors()) { return; } } @Override void setCssRenamingMap(CssRenamingMap map) { options_.cssRenamingMap = map; } @Override CssRenamingMap getCssRenamingMap() { return options_.cssRenamingMap; } /** * Reprocesses the current defines over the AST. This is used by GwtCompiler * to generate N outputs for different targets from the same (checked) AST. * For each target, we apply the target-specific defines by calling * {@code processDefines} and then {@code optimize} to optimize the AST * specifically for that target. */ public void processDefines() { (new DefaultPassConfig(options_)).processDefines.create(this) .process(externsRoot, jsRoot); } boolean isInliningForbidden() { return options_.propertyRenaming == PropertyRenamingPolicy

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.javascript.jscomp.parsing.ParserRunner; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.io.IOException; import java.util.logging.Logger; /** * Generates an AST for a JavaScript source file. * * */ public class JsAst implements SourceAst { private static final Logger logger_ = Logger.getLogger(JsAst.class.getName()); private static final long serialVersionUID = 1L; private transient SourceFile sourceFile; private String fileName; private Node root; public JsAst(SourceFile sourceFile) { this.sourceFile = sourceFile; this.fileName = sourceFile.getName(); } @Override public Node getAstRoot(AbstractCompiler compiler) { if (root == null) { createAst(compiler); } return root; } @Override public void clearAst() { root = null; // While we're at it, clear out any saved text in the source file on // the assumption that if we're dumping the parse tree, then we probably // assume regenerating everything else is a smart idea also. sourceFile.clearCachedSource(); } @Override public SourceFile getSourceFile() { return sourceFile; } @Override public void setSourceFile(SourceFile file) { Preconditions.checkState(fileName.equals(file.getName())); sourceFile = file; } private void createAst(AbstractCompiler compiler)

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>String propertyName) { return hasProperty(propertyName); } /** Returns the names of all the properties directly on this type. */ public Set<String> getOwnPropertyNames() { return new HashSet<String>(); } /** * Checks whether the property's type is inferred. */ public abstract boolean isPropertyTypeInferred(String propertyName); /** * Checks whether the property's type is declared. */ public abstract boolean isPropertyTypeDeclared(String propertyName); /** * Whether the given property is declared on this object. */ boolean hasOwnDeclaredProperty(String name) { return hasOwnProperty(name) && isPropertyTypeDeclared(name); } /** Checks whether the property was defined in the externs. */ public boolean isPropertyInExterns(String propertyName) { return false; } /** * Gets the number of properties of this object. */ public abstract int getPropertiesCount(); /** * Returns a list of properties defined or inferred on this type and any of * its supertypes. */ public Set<String> getPropertyNames() { Set<String> props = Sets.newHashSet(); collectPropertyNames(props); return props; } /** * Adds any properties defined on this type or its supertypes to the set. */ abstract void collectPropertyNames(Set<String> props); @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseObjectType(this); } /** * Checks that the prototype is an implicit prototype of this object. Since * each object has an implicit prototype, an implicit prototype's * implicit prototype is also this implicit prototype's. * * @param prototype any prototype based object * * @return {@code true} if {@code prototype} is {@code equal} to any * object in this object's implicit prototype chain. */ final boolean isImplicitPrototype(ObjectType prototype) { for (ObjectType current = this; current != null; current = current.getImplicitPrototype()) { if (current.equals(prototype)) { return true; } } return false; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.TRUE; } /** * We treat this as the unknown

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> /** * Create a named type based on the reference. */ public NamedType(JSTypeRegistry registry, String reference, String sourceName, int lineno, int charno) { super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); Preconditions.checkNotNull(reference); this.reference = reference; this.sourceName = sourceName; this.lineno = lineno; this.charno = charno; } @Override public void forgiveUnknownNames() { forgiving = true; } /** Returns the type to which this refers (which is unknown if unresolved). */ public JSType getReferencedType() { return referencedType; } @Override public String getReferenceName() { return reference; } @Override public String toString() { return reference; } @Override public boolean hasReferenceName() { return true; } @Override public boolean isNamedType() { return true; } @Override public boolean isNominalType() { return true; } /** * Two named types are equal if they are the same {@code ObjectType} object. * This is complicated by the fact that equals is sometimes called before we * have a chance to resolve the type names. * * @return {@code true} iff {@code that} == {@code this} or {@code that} * is a {@link NamedType} whose reference is the same as ours, * or {@code that} is the type we reference. */ @Override public boolean equals(Object that) { if (this == that) { return true; } else if (that instanceof JSType) { ObjectType objType = ObjectType.cast((JSType) that); if (objType != null) { return objType.isNominalType() && reference.equals(objType.getReferenceName()); } } return false; } @Override public int hashCode() { return reference.hashCode(); } /** * Resolve the referenced type within the enclosing scope. */ @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) { // TODO(user): Investigate whether it is really necessary to keep two // different

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>/* * Copyright 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.JSType; /** * <p>The syntactic scope creator scans the parse tree to create a Scope object * containing all the variable declarations in that scope.</p> * * <p>This implementation is not thread-safe.</p> * * */ class SyntacticScopeCreator implements ScopeCreator { private final AbstractCompiler compiler; private Scope scope; private String sourceName; private final RedeclarationHandler redeclarationHandler; // The arguments variable is special, in that it's declared in every local // scope, but not explicitly declared. private static final String ARGUMENTS = "arguments"; public static final DiagnosticType VAR_MULTIPLY_DECLARED_ERROR = DiagnosticType.error( "JSC_VAR_MULTIPLY_DECLARED_ERROR", "Variable {0} first declared in {1}"); /** * Creates a ScopeCreator. */ SyntacticScopeCreator(AbstractCompiler compiler) { this.compiler = compiler; this.redeclarationHandler = new DefaultRedeclarationHandler(); } SyntacticScopeCreator( AbstractCompiler compiler, RedeclarationHandler redeclarationHandler) { this.compiler = compiler; this.redeclarationHandler = redeclarationHandler; } public Scope createScope(Node n, Scope parent) { sourceName =

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> null; if (parent == null) { scope = new Scope(n, compiler); } else { scope = new Scope(parent, n); } scanRoot(n, parent); sourceName = null; Scope returnedScope = scope; scope = null; return returnedScope; } private void scanRoot(Node n, Scope parent) { if (n.getType() == Token.FUNCTION) { sourceName = (String) n.getProp(Node.SOURCENAME_PROP); final Node fnNameNode = n.getFirstChild(); final Node args = fnNameNode.getNext(); final Node body = args.getNext(); // Bleed the function name into the scope, if it hasn't // been declared in the outer scope. String fnName = fnNameNode.getString(); if (!fnName.isEmpty() && NodeUtil.isFunctionAnonymous(n)) { declareVar(fnName, fnNameNode, n, null, null, n); } // Args: Declare function variables Preconditions.checkState(args.getType() == Token.LP); for (Node a = args.getFirstChild(); a != null; a = a.getNext()) { Preconditions.checkState(a.getType() == Token.NAME); declareVar(a.getString(), a, args, n, null, n); } // Body scanVars(body, n); } else { // It's the global block Preconditions.checkState(scope.getParent() == null); scanVars(n, null); } } /** * Scans and gather variables declarations under a Node */ private void scanVars(Node n, Node parent) { switch (n.getType()) { case Token.VAR: // Declare all variables. e.g. var x = 1, y, z; for (Node child = n.getFirstChild(); child != null;) { Node next = child.getNext(); Preconditions.checkState(child.getType() == Token.NAME); String name = child.getString(); declareVar(name, child, n, parent, null, n); child = next; } return; case Token.FUNCTION: if (NodeUtil.isFunctionAnonymous(n)) { return; }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> String fnName = n.getFirstChild().getString(); if (fnName.isEmpty()) { // This is invalid, but allow it so the checks can catch it. return; } declareVar(fnName, n.getFirstChild(), n, parent, null, n); return; // should not examine function's children case Token.CATCH: Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getFirstChild().getType() == Token.NAME); // the first child is the catch var and the third child // is the code block final Node var = n.getFirstChild(); final Node block = var.getNext().getNext(); declareVar(var.getString(), var, n, parent, null, n); scanVars(block, n); return; // only one child to scan case Token.SCRIPT: sourceName = (String) n.getProp(Node.SOURCENAME_PROP); break; } // Variables can only occur in statement-level nodes, so // we only need to traverse children in a couple special cases. if (NodeUtil.isControlStructure(n) || NodeUtil.isStatementBlock(n)) { for (Node child = n.getFirstChild(); child != null;) { Node next = child.getNext(); scanVars(child, n); child = next; } } } /** * Interface for injectable duplicate handling. */ interface RedeclarationHandler { void onRedeclaration( Scope s, String name, Node n, Node parent, Node gramps, Node nodeWithLineNumber); } /** * The default handler for duplicate declarations. */ private class DefaultRedeclarationHandler implements RedeclarationHandler { public void onRedeclaration( Scope s, String name, Node n, Node parent, Node gramps, Node nodeWithLineNumber) { // Don't allow multiple variables to be declared at the top level scope if (scope.isGlobal()) { Scope.Var origVar = scope.getVar(name); Node origParent = origVar.getParentNode(); if (origParent.getType() == Token.CATCH && parent.getType() == Token.CATCH) { // Okay, both are 'catch(x)' variables. return

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>; } boolean allowDupe = false; JSDocInfo info = n.getJSDocInfo(); if (info == null) { info = parent.getJSDocInfo(); } allowDupe = info != null && info.getSuppressions().contains("duplicate"); if (!allowDupe) { compiler.report( JSError.make(sourceName, nodeWithLineNumber, VAR_MULTIPLY_DECLARED_ERROR, name, (origVar.input != null ? origVar.input.getName() : "??"))); } } } } /** * Declares a variable. * * @param name The variable name * @param n The node corresponding to the variable name (usually a NAME node) * @param parent The parent node of {@code n} * @param gramps The parent node of {@code parent} * @param declaredType The variable's type, according to JSDoc * @param nodeWithLineNumber The node to use to access the line number of * the variable declaration, if needed */ private void declareVar(String name, Node n, Node parent, Node gramps, JSType declaredType, Node nodeWithLineNumber) { if (scope.isDeclared(name, false) || (scope.isLocal() && name.equals(ARGUMENTS))) { redeclarationHandler.onRedeclaration( scope, name, n, parent, gramps, nodeWithLineNumber); } else { scope.declare(name, n, declaredType, compiler.getInput(sourceName)); } } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.JSType; import com.google.javascript.rhino.jstype.ObjectType; import java.nio.charset.Charset; /** * A code generator that outputs type annotations for functions and * constructors. * */ class TypedCodeGenerator extends CodeGenerator { TypedCodeGenerator(CodeConsumer consumer, Charset outputCharset) { super(consumer, outputCharset, true); } @Override void add(Node n, Context context) { Node parent = n.getParent(); if (parent.getType() == Token.BLOCK || parent.getType() == Token.SCRIPT) { if (n.getType() == Token.FUNCTION) { add(getFunctionAnnotation(n)); } else if (n.getType() == Token.EXPR_RESULT && n.getFirstChild().getType() == Token.ASSIGN) { Node rhs = n.getFirstChild().getFirstChild(); add(getTypeAnnotation(rhs)); } else if (n.getType() == Token.VAR && n.getFirstChild().getFirstChild() != null && n.getFirstChild().getFirstChild().getType() == Token.FUNCTION) { add(getFunctionAnnotation(n.getFirstChild().getFirstChild())); } } super.add(n, context); } private String getTypeAnnotation(Node node) { JSType type = node.getJSType();

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> if (type instanceof FunctionType) { return getFunctionAnnotation(node); } else if (type != null && !type.isUnknownType() && !type.isEmptyType() && !type.isVoidType()) { return "/** @type {" + node.getJSType() + "} */\n"; } else { return ""; } } /** * @param node A node for a function for which to generate a type annotation */ private String getFunctionAnnotation(Node node) { StringBuilder sb = new StringBuilder("/**\n"); if (node.getJSType().isUnknownType()) { return ""; } FunctionType funType = (FunctionType) node.getJSType(); // We need to use the child nodes of the function as the nodes for the // parameters of the function type do not have the real parameter names. // FUNCTION // NAME // LP // NAME param1 // NAME param2 Node fnNode = funType.getSource(); if (fnNode != null) { Node paramNode = NodeUtil.getFnParameters(fnNode).getFirstChild(); // Param types for (Node n : funType.getParameters()) { // Bail out if the paramNode is not there. if (paramNode == null) { break; } sb.append(" * @param {" + n.getJSType() + "} "); sb.append(paramNode.getString()); sb.append("\n"); paramNode = paramNode.getNext(); } } // Return type JSType retType = funType.getReturnType(); if (retType != null && !retType.isUnknownType() && !retType.isEmptyType()) { sb.append(" * @return {" + retType + "}\n"); } // Constructor/interface if (funType.isConstructor() || funType.isInterface()) { ObjectType superInstance = funType.getSuperClassConstructor().getInstanceType(); if (!superInstance.toString().equals("Object")) { sb.append(" * @extends {" + superInstance + "}\n"); } for (ObjectType interfaze : funType.getImplementedInterfaces()) { sb.append(" * @implements {" + interfaze + "}\n"); }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Map; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new ContextualRenameInverter(compiler); }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> @Override public void enterScope(NodeTraversal t) { Node declarationRoot = t.getScopeRoot(); Renamer renamer; if (nameStack.isEmpty()) { // If the contextual renamer is being used the starting context can not // be a function. Preconditions.checkState( declarationRoot.getType() != Token.FUNCTION || !(rootRenamer instanceof ContextualRenamer)); Preconditions.checkState(t.inGlobalScope()); renamer = rootRenamer; } else { renamer = nameStack.peek().forChildScope(); } if (declarationRoot.getType() == Token.FUNCTION) { // Add the function parameters Node fnParams = declarationRoot.getFirstChild().getNext(); for (Node c = fnParams.getFirstChild(); c != null; c = c.getNext()) { String name = c.getString(); renamer.addDeclaredName(name); } // Add the function body declarations Node functionBody = declarationRoot.getLastChild(); findDeclaredNames(functionBody, null, renamer); } else { // Add the block declarations findDeclaredNames(declarationRoot, null, renamer); } nameStack.push(renamer); } @Override public void exitScope(NodeTraversal t) { if (!t.inGlobalScope()) { nameStack.pop(); } } @Override public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.FUNCTION: { // Add recursive function name, if needed. // NOTE: "enterScope" is called after we need to pick up this name. Renamer renamer = nameStack.peek().forChildScope(); // If needed, add the function recursive name. String name = n.getFirstChild().getString(); if (name != null && !name.isEmpty() && parent != null && !NodeUtil.isFunctionDeclaration(n)) { renamer.addDeclaredName(name); } nameStack.push(renamer); } break; case Token.CATCH: { Renamer renamer = nameStack.peek().forChildScope(); String name = n.getFirstChild().getString(); renam

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>er.addDeclaredName(name); nameStack.push(renamer); } break; } return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.NAME: String newName = getReplacementName(n.getString()); if (newName != null) { Renamer renamer = nameStack.peek(); if (renamer.stripConstIfReplaced()) { // TODO(johnlenz): Do we need to do anything about the javadoc? n.removeProp(Node.IS_CONSTANT_NAME); } n.setString(newName); t.getCompiler().reportCodeChange(); } break; case Token.FUNCTION: // Remove function recursive name (if any). nameStack.pop(); break; case Token.CATCH: // Remove catch except name from the stack of names. nameStack.pop(); break; } } /** * Walks the stack of name maps and finds the replacement name for the * current scope. */ private String getReplacementName(String oldName) { for (Renamer names : nameStack) { String newName = names.getReplacementName(oldName); if (newName != null) { return newName; } } return null; } /** * Traverses the current scope and collects declared names. Does not * decent into functions or add CATCH exceptions. */ private void findDeclaredNames(Node n, Node parent, Renamer renamer) { // Do a shallow traversal, so don't traverse into function declarations, // except for the name of the function itself. if (parent == null || parent.getType() != Token.FUNCTION || n == parent.getFirstChild()) { if (NodeUtil.isVarDeclaration(n)) { renamer.addDeclaredName(n.getString()); } else if (NodeUtil.isFunctionDeclaration(n)) { Node nameNode = n.getFirstChild(); renamer.addDeclaredName(nameNode.getString()); } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { findDeclaredNames(c, n, renam

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>er); } } } /** * Declared names renaming policy interface. */ interface Renamer { /** * Called when a declared name is found in the local current scope. */ void addDeclaredName(String name); /** * @return A replacement name, null if oldName is unknown or should not * be replaced. */ String getReplacementName(String oldName); /** * @return Whether the constant-ness of a name should be removed. */ boolean stripConstIfReplaced(); /** * @return A Renamer for a scope within the scope of the current Renamer. */ Renamer forChildScope(); } /** * Inverts the transformation by {@link ContextualRenamer}, when possible. */ static class ContextualRenameInverter extends AbstractPostOrderCallback implements CompilerPass { private final AbstractCompiler compiler; // A mapping from long names to short ones. private Map<Var, String> nameMap = Maps.newHashMap(); private ContextualRenameInverter(AbstractCompiler compiler) { this.compiler = compiler; } public void process(Node externs, Node js) { NodeTraversal.traverse(compiler, js, this); } public static String getOrginalName(String name) { int index = indexOfSeparator(name); return (index == -1) ? name : name.substring(0, index); } private static int indexOfSeparator(String name) { return name.lastIndexOf(ContextualRenamer.UNIQUE_ID_SEPARATOR); } private static String getOrginalNameInternal(String name, int index) { return name.substring(0, index); } private static String getNameSuffix(String name, int index) { return name.substring( index + ContextualRenamer.UNIQUE_ID_SEPARATOR.length(), name.length()); } @Override public void visit(NodeTraversal t, Node node, Node parent) { if (node.getType() == Token.NAME) { String oldName = node.getString(); if (oldName.indexOf(ContextualRenamer.UNIQUE_ID_SEPARATOR) != -1) { Scope scope = t.getScope(); Var var = t.getScope().getVar(oldName); if (var

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> == null || var.isGlobal()) { return; } if (nameMap.containsKey(var)) { node.setString(nameMap.get(var)); } else { int index = indexOfSeparator(oldName); String newName = getOrginalNameInternal(oldName, index); String suffix = getNameSuffix(oldName, index); // The convention we are using here is that names of the form: // a$$1 ($$ followed by a digit are allowed to mask a global) // a$$inline_1 ($$ followed by anything that isn't a digit isn't // allowed to mask a global. // This preserves existing behavior while allowing simpler diffs // when inlining is enabled. // TODO(johnlenz): Remove this distiction when scoping is properly // checked. boolean recurseScopes = false; if (!suffix.matches("\\d+")) { // Non-contextual renamed value. recurseScopes = true; } // Before we change the name of this variable, double-check to // make sure we're not declaring a duplicate name in the // same scope as the var declaration. // TODO(johnlenz): This test isn't sufficient; specifically, // a reference to a global may have been introduced. Shortening // the name without checking for such a reference may mask the // global causing the wrong value to be referenced. if (var.scope.isDeclared(newName, recurseScopes) || !TokenStream.isJSIdentifier(newName)) { newName = oldName; } else { var.scope.declare(newName, var.nameNode, null, null); // Handle bleeding functions. Node parentNode = var.getParentNode(); if (parentNode.getType() == Token.FUNCTION && parentNode == var.scope.getRootNode()) { var.getNameNode().setString(newName); } node.setString(newName); compiler.reportCodeChange(); } nameMap.put(var, newName); } } } } } /** * Rename every locally name to be unique, the first encountered declaration * (specifically global names) are left in their original form. Those that are * renamed are made unique by giving them a unique suffix based on *

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> the number of declarations of the name. * * The root ContextualRenamer is assumed to be in GlobalScope. * * Used by the Normalize pass. * @see Normalize */ static class ContextualRenamer implements Renamer { private final Multiset<String> nameUsage; private final Map<String, String> declarations = Maps.newHashMap(); private final boolean global; final static String UNIQUE_ID_SEPARATOR = "$$"; ContextualRenamer() { this.global = true; nameUsage = HashMultiset.create(); } /** * Constructor for child scopes. */ private ContextualRenamer(Multiset<String> nameUsage) { this.global = false; this.nameUsage = nameUsage; } /** * Create a ContextualRenamer */ @Override public Renamer forChildScope() { return new ContextualRenamer(nameUsage); } /** * Adds a name to the map of names declared in this scope. */ @Override public void addDeclaredName(String name) { if (global) { reserveName(name); } else { // It hasn't been declared locally yet, so increment the count. if (!declarations.containsKey(name)) { int id = incrementNameCount(name); String newName = null; if (id != 0) { newName = getUniqueName(name, id); } declarations.put(name, newName); } } } @Override public String getReplacementName(String oldName) { return declarations.get(oldName); } /** * Given a name and the associated id, create a new unique name. */ private String getUniqueName(String name, int id) { return name + UNIQUE_ID_SEPARATOR + id; } private void reserveName(String name) { nameUsage.setCount(name, 0, 1); } private int incrementNameCount(String name) { return nameUsage.add(name, 1); } @Override public boolean stripConstIfReplaced() { return false; } } /** * Rename every declared name to be unique. Typically this would be used * when injecting code to insure that

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>) { return referencedType.canAssignTo(that); } @Override public boolean equals(Object that) { if (this == that) { return true; } return referencedType.equals(that); } @Override public int hashCode() { return referencedType.hashCode(); } @Override public String toString() { return referencedType.toString(); } @Override public ObjectType getImplicitPrototype() { return referencedType.getImplicitPrototype(); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { return referencedType.defineProperty(propertyName, type, inferred, inExterns); } @Override public boolean isPropertyTypeDeclared(String propertyName) { return referencedType.isPropertyTypeDeclared(propertyName); } @Override public boolean isPropertyTypeInferred(String propertyName) { return referencedType.isPropertyTypeInferred(propertyName); } @Override public boolean isPropertyInExterns(String propertyName) { return referencedType.isPropertyInExterns(propertyName); } @Override public int getPropertiesCount() { return referencedType.getPropertiesCount(); } @Override protected void collectPropertyNames(Set<String> props) { referencedType.collectPropertyNames(props); } @Override public JSType findPropertyType(String propertyName) { return referencedType.findPropertyType(propertyName); } @Override public JSType getPropertyType(String propertyName) { return referencedType.getPropertyType(propertyName); } @Override public JSDocInfo getJSDocInfo() { return referencedType.getJSDocInfo(); } @Override public void setJSDocInfo(JSDocInfo info) { referencedType.setJSDocInfo(info); } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { return referencedType.getOwnPropertyJSDocInfo(propertyName); } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { referencedType.setPropertyJSDocInfo(propertyName, info, inExterns); } @Override public boolean hasProperty(String propertyName) {

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> private JSType currentClass = null; CheckAccessControls(AbstractCompiler compiler) { this.compiler = compiler; this.validator = compiler.getTypeValidator(); } public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, root, this); } public void enterScope(NodeTraversal t) { if (!t.inGlobalScope()) { Node n = t.getScopeRoot(); Node parent = n.getParent(); if (isDeprecatedFunction(n, parent)) { deprecatedDepth++; } if (methodDepth == 0) { currentClass = getClassOfMethod(n, parent); } methodDepth++; } } public void exitScope(NodeTraversal t) { if (!t.inGlobalScope()) { Node n = t.getScopeRoot(); Node parent = n.getParent(); if (isDeprecatedFunction(n, parent)) { deprecatedDepth--; } methodDepth--; if (methodDepth == 0) { currentClass = null; } } } /** * Gets the type of the class that "owns" a method, or null if * we know that its un-owned. */ private JSType getClassOfMethod(Node n, Node parent) { if (parent.getType() == Token.ASSIGN) { Node lValue = parent.getFirstChild(); if (lValue.isQualifiedName()) { if (lValue.getType() == Token.GETPROP) { // We have an assignment of the form "a.b = ...". JSType lValueType = lValue.getJSType(); if (lValueType != null && lValueType.isConstructor()) { // If a.b is a constructor, then everything in this function // belongs to the "a.b" type. return ((FunctionType) lValueType).getInstanceType(); } else { // If a.b is not a constructor, then treat this as a method // of whatever type is on "a". return normalizeClassType(lValue.getFirstChild().getJSType()); } } else { // We have an assignment of the form "a = ...", so pull the // type off the "a". return normalizeClassType(lValue.getJSType()); } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> } else if (NodeUtil.isFunctionDeclaration(n) || parent.getType() == Token.NAME) { return normalizeClassType(n.getJSType()); } return null; } /** * Normalize the type of a constructor, its instance, and its prototype * all down to the same type (the instance type). */ private JSType normalizeClassType(JSType type) { if (type == null || type.isUnknownType()) { return type; } else if (type.isConstructor()) { return ((FunctionType) type).getInstanceType(); } else if (type.isFunctionPrototypeType()) { FunctionType owner = ((FunctionPrototypeType) type).getOwnerFunction(); if (owner.isConstructor()) { return owner.getInstanceType(); } } return type; } public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { return true; } public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.NAME: checkNameDeprecation(t, n, parent); checkNameVisibility(t, n, parent); break; case Token.GETPROP: checkPropertyDeprecation(t, n, parent); checkPropertyVisibility(t, n, parent); break; case Token.NEW: checkConstructorDeprecation(t, n, parent); break; } } /** * Checks the given NEW node to ensure that access restrictions are obeyed. */ private void checkConstructorDeprecation(NodeTraversal t, Node n, Node parent) { JSType type = n.getJSType(); if (type != null) { String deprecationInfo = getTypeDeprecationInfo(type); if (deprecationInfo != null && shouldEmitDeprecationWarning(t, n, parent)) { if (!deprecationInfo.isEmpty()) { compiler.report( JSError.make(t, n, DEPRECATED_CLASS_REASON, type.toString(), deprecationInfo)); } else { compiler.report( JSError.make(t, n, DEPRECATED_CLASS, type.toString())); } } } } /** * Checks the given NAME node to ensure that access restrictions are obeyed. */ private

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> void checkNameDeprecation(NodeTraversal t, Node n, Node parent) { // Don't bother checking definitions or constructors. if (parent.getType() == Token.FUNCTION || parent.getType() == Token.VAR || parent.getType() == Token.NEW) { return; } Scope.Var var = t.getScope().getVar(n.getString()); JSDocInfo docInfo = var == null ? null : var.getJSDocInfo(); if (docInfo != null && docInfo.isDeprecated() && shouldEmitDeprecationWarning(t, n, parent)) { if (docInfo.getDeprecationReason() != null) { compiler.report( JSError.make(t, n, DEPRECATED_NAME_REASON, n.getString(), docInfo.getDeprecationReason())); } else { compiler.report( JSError.make(t, n, DEPRECATED_NAME, n.getString())); } } } /** * Checks the given GETPROP node to ensure that access restrictions are * obeyed. */ private void checkPropertyDeprecation(NodeTraversal t, Node n, Node parent) { // Don't bother checking constructors. if (parent.getType() == Token.NEW) { return; } ObjectType objectType = ObjectType.cast(dereference(n.getFirstChild().getJSType())); String propertyName = n.getLastChild().getString(); if (objectType != null) { String deprecationInfo = getPropertyDeprecationInfo(objectType, propertyName); if (deprecationInfo != null && shouldEmitDeprecationWarning(t, n, parent)) { if (!deprecationInfo.isEmpty()) { compiler.report( JSError.make(t, n, DEPRECATED_PROP_REASON, propertyName, validator.getReadableJSTypeName(n.getFirstChild(), true), deprecationInfo)); } else { compiler.report( JSError.make(t, n, DEPRECATED_PROP, propertyName, validator.getReadableJSTypeName(n.getFirstChild(), true))); } } } } /** * Determines whether the given name is visible in the current context. * @param t The current traversal. * @param name The name node. */ private void checkNameVisibility(

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>NodeTraversal t, Node name, Node parent) { Var var = t.getScope().getVar(name.getString()); if (var != null) { JSDocInfo docInfo = var.getJSDocInfo(); if (docInfo != null) { // If a name is private, make sure that we're in the same file. Visibility visibility = docInfo.getVisibility(); if (visibility == Visibility.PRIVATE && !t.getInput().getName().equals(docInfo.getSourceName())) { if (docInfo.isConstructor() && isValidPrivateConstructorAccess(parent)) { return; } compiler.report( JSError.make(t, name, BAD_PRIVATE_GLOBAL_ACCESS, name.getString(), docInfo.getSourceName())); } } } } /** * Determines whether the given property is visible in the current context. * @param t The current traversal. * @param getprop The getprop node. */ private void checkPropertyVisibility(NodeTraversal t, Node getprop, Node parent) { ObjectType objectType = ObjectType.cast(dereference(getprop.getFirstChild().getJSType())); String propertyName = getprop.getLastChild().getString(); if (objectType != null) { // Is this a normal property access, or are we trying to override // an existing property? boolean isOverride = t.inGlobalScope() && parent.getType() == Token.ASSIGN && parent.getFirstChild() == getprop; // Find the lowest property defined on a class with visibility // information. if (isOverride) { objectType = objectType.getImplicitPrototype(); } JSDocInfo docInfo = null; for (; objectType != null; objectType = objectType.getImplicitPrototype()) { docInfo = objectType.getOwnPropertyJSDocInfo(propertyName); if (docInfo != null && docInfo.getVisibility() != Visibility.INHERITED) { break; } } if (objectType == null) { // We couldn't find a visibility modifier; assume it's public. return; } boolean sameInput = t.getInput().getName().equals(docInfo.getSourceName()); Visibility visibility = docInfo.getVisibility(); JSType owner

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> } /** * Whether the given access of a private constructor is legal. * * For example, * new PrivateCtor_(); // not legal * PrivateCtor_.newInstance(); // legal * x instanceof PrivateCtor_ // legal * * This is a weird special case, because our visibility system is inherited * from Java, and JavaScript has no distinction between classes and * constructors like Java does. * * We may want to revisit this if we decide to make the restrictions tighter. */ private static boolean isValidPrivateConstructorAccess(Node parent) { return parent.getType() != Token.NEW; } /** * Determines whether a deprecation warning should be emitted. * @param t The current traversal. * @param n The node which we are checking. * @param parent The parent of the node which we are checking. */ private boolean shouldEmitDeprecationWarning( NodeTraversal t, Node n, Node parent) { // In the global scope, there are only two kinds of accesses that should // be flagged for warnings: // 1) Calls of deprecated functions and methods. // 2) Instantiations of deprecated classes. // For now, we just let everything else by. if (t.inGlobalScope()) { if (!((parent.getType() == Token.CALL && parent.getFirstChild() == n) || n.getType() == Token.NEW)) { return false; } } // We can always assign to a deprecated property, to keep it up to date. if (n.getType() == Token.GETPROP && n == parent.getFirstChild() && NodeUtil.isAssignmentOp(parent)) { return false; } return !canAccessDeprecatedTypes(t); } /** * Returns whether it's currently ok to access deprecated names and * properties. * * There are 3 exceptions when we're allowed to use a deprecated * type or property: * 1) When we're in a deprecated function. * 2) When we're in a deprecated class. * 3) When we're in a static method of a deprecated class. */ private boolean canAccessDeprecatedTypes(NodeTraversal t) { Node scopeRoot = t.getScopeRoot(); Node scopeRootParent = scopeRoot.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>getParent(); return // Case #1 (deprecatedDepth > 0) || // Case #2 (getTypeDeprecationInfo(t.getScope().getTypeOfThis()) != null) || // Case #3 (scopeRootParent != null && scopeRootParent.getType() == Token.ASSIGN && getTypeDeprecationInfo( getClassOfMethod(scopeRoot, scopeRootParent)) != null); } /** * Returns whether this is a function node annotated as deprecated. */ private static boolean isDeprecatedFunction(Node n, Node parent) { if (n.getType() == Token.FUNCTION) { JSType type = n.getJSType(); if (type != null) { return getTypeDeprecationInfo(type) != null; } } return false; } /** * Returns the deprecation reason for the type if it is marked * as being deprecated. Returns empty string if the type is deprecated * but no reason was given. Returns null if the type is not deprecated. */ private static String getTypeDeprecationInfo(JSType type) { if (type == null) { return null; } JSDocInfo info = type.getJSDocInfo(); if (info != null && info.isDeprecated()) { if (info.getDeprecationReason() != null) { return info.getDeprecationReason(); } return ""; } ObjectType objType = ObjectType.cast(type); if (objType != null) { ObjectType implicitProto = objType.getImplicitPrototype(); if (implicitProto != null) { return getTypeDeprecationInfo(implicitProto); } } return null; } /** * Returns the deprecation reason for the property if it is marked * as being deprecated. Returns empty string if the property is deprecated * but no reason was given. Returns null if the property is not deprecated. */ private static String getPropertyDeprecationInfo(ObjectType type, String prop) { JSDocInfo info = type.getOwnPropertyJSDocInfo(prop); if (info != null && info.isDeprecated()) { if (info.getDeprecationReason() != null) { return info.getDeprecationReason(); } return ""; } ObjectType implicitProto = type.getImplicitPrototype(); if

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> argument(s)"); static final DiagnosticType VAR_ARGS_ERROR = DiagnosticType.error( "JSC_VAR_ARGS_ERROR", "Argument must precede var_args argument"); FunctionCheck(AbstractCompiler compiler, CheckLevel level) { this.compiler = compiler; this.level = level; this.functionInfos = new HashMap<Node, FunctionInfo>(); } public void process(Node externs, Node root) { NodeTraversal.traverseRoots(compiler, Lists.newArrayList(externs, root), new ArgCheck()); } /** * Contains information about the number of args a function accepts. */ static class FunctionInfo { final int args; final int optionalArgs; final boolean hasVarArgs; FunctionInfo(int args, int optionalArgs, boolean hasVarArgs) { this.args = args; this.optionalArgs = optionalArgs; this.hasVarArgs = hasVarArgs; } @Override public boolean equals(Object other) { if (!(other instanceof FunctionInfo)) { return false; } FunctionInfo o = (FunctionInfo) other; return o.args == args && o.optionalArgs == optionalArgs && o.hasVarArgs == hasVarArgs; } @Override public int hashCode() { int result = 17; result = 37 * result + args; result = 37 * result + optionalArgs; result = 37 * result + (hasVarArgs ? 1 : 0); return result; } @Override public String toString() { return args + " total argument(s) " + "of which " + optionalArgs + " is/are optional" + (hasVarArgs ? ", var_args supported" : ""); } } /** * Second pass: look at the function calls and check that the number of * arguments are okay. */ class ArgCheck extends AbstractPostOrderCallback { public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.NEW: case Token.CALL: Node fn = n.getFirstChild(); if (fn.getType() == Token.NAME) { String fnName = fn.getString(); // Lookup the function Scope.Var v

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> = t.getScope().getVar(fnName); // VarCheck should have caught this undefined function if (v == null) { return; } Node fnDef = v.getInitialValue(); if (fnDef == null || fnDef.getType() != Token.FUNCTION) { // It's a variable, can't check this. return; } FunctionInfo f = getFunctionInfo(fnDef, v.getInputName()); checkCall(n, fnName, Collections.singletonList(f), t, level); } break; } } } static void checkCall(Node n, String fnName, Iterable<FunctionInfo> infos, NodeTraversal t, CheckLevel level) { int count = n.getChildCount() - 1; boolean matched = false; int minArgs = Integer.MAX_VALUE; int maxArgs = Integer.MIN_VALUE; for (FunctionInfo f : infos) { int requiredCount = f.args - f.optionalArgs; if (count >= requiredCount && (count <= f.args || f.hasVarArgs)) { matched = true; break; } minArgs = Math.min(minArgs, requiredCount); maxArgs = Math.max(maxArgs, f.hasVarArgs ? Integer.MAX_VALUE : f.args); } if (!matched) { t.getCompiler().report( JSError.make(t, n, level, WRONG_ARGUMENT_COUNT_ERROR, fnName, String.valueOf(count), String.valueOf(minArgs), maxArgs != Integer.MAX_VALUE ? " and no more than " + maxArgs + " argument(s)" : "")); } } /** * Gets a {@link FunctionInfo} instance containing information about a * particular function's arguments. Caches the result for faster handling of * repeated queries. * * @param fn A FUNCTION node * @param fnSourceName The name of the script source in which the function is * defined (for formatting error/warning messages) */ FunctionInfo getFunctionInfo(Node fn, String fnSourceName) { FunctionInfo fi = functionInfos.get(fn); if (fi == null) { fi = createFunctionInfo

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> ObjectPropertyStringPostprocess(compiler); } }; /** * Renames properties so that the two properties that never appear on * the same object get the same name. */ private final PassFactory ambiguateProperties = new PassFactory("ambiguateProperties", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new AmbiguateProperties( compiler, options.anonymousFunctionNaming.getReservedCharacters()); } }; /** Denormalize the AST for code generation. */ private final PassFactory denormalize = new PassFactory("denormalize", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { compiler.setUnnormalized(); return new Denormalize(compiler); } }; /** Inverting name normalization. */ private final PassFactory invertContextualRenaming = new PassFactory("invertNames", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return MakeDeclaredNamesUnique.getContextualRenameInverter(compiler); } }; /** * Renames properties. */ private final PassFactory renameProperties = new PassFactory("renameProperties", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { VariableMap map = null; if (options.inputPropertyMapSerialized != null) { try { map = VariableMap.fromBytes(options.inputPropertyMapSerialized); } catch (ParseException e) { return new ErrorPass(compiler, JSError.make(INPUT_MAP_PROP_PARSE, e.getMessage())); } } final VariableMap prevPropertyMap = map; return new CompilerPass() { @Override public void process(Node externs, Node root) { propertyMap = runPropertyRenaming( compiler, prevPropertyMap, externs, root); } }; } }; private VariableMap runPropertyRenaming( AbstractCompiler compiler, VariableMap prevPropertyMap, Node externs, Node root) { char[] reservedChars = options.anonymousFunctionNaming.getReservedCharacters(); switch (options.propertyRenaming) { case HEURISTIC: RenamePrototypes rproto = new RenamePrototypes(compiler, false, reservedChars, prevPropertyMap); rproto.process

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> FunctionParamBuilder(JSTypeRegistry registry) { this.registry = registry; } /** * Add parameters of the given type to the end of the param list. * @return False if this is called after optional params are added. */ public boolean addRequiredParams(JSType ...types) { if (hasOptionalOrVarArgs()) { return false; } for (JSType type : types) { newParameter(type); } return true; } /** * Add optional parameters of the given type to the end of the param list. * @param types Types for each optional parameter. The builder will make them * undefineable. * @return False if this is called after var args are added. */ public boolean addOptionalParams(JSType ...types) { if (hasVarArgs()) { return false; } for (JSType type : types) { newParameter(registry.createOptionalType(type)).setOptionalArg(true); } return true; } /** * Add variable arguments to the end of the parameter list. * @return False if this is called after var args are added. */ public boolean addVarArgs(JSType type) { if (hasVarArgs()) { return false; } // There are two types of variable argument functions: // 1) Programmer-defined var args // 2) Native bottom types that can accept any argument. // For the first one, "undefined" is a valid value for all arguments. // For the second, we do not want to cast it up to undefined. if (!type.isEmptyType()) { type = registry.createOptionalType(type); } newParameter(type).setVarArgs(true); return true; } /** * Copies the parameter specification from the given node. */ public void newParameterFromNode(Node n) { Node newParam = newParameter(n.getJSType()); newParam.setVarArgs(n.isVarArgs()); newParam.setOptionalArg(n.isOptionalArg()); } // Add a parameter to the list with the given type. private Node newParameter(JSType type) { Node paramNode = Node.newString(Token.NAME, "");

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> determining provided dependencies amongst different * js scripts. */ public String extractClassNameIfProvide(Node node, Node parent); /** * Convenience method for determining required dependencies amongst different * js scripts. */ public String extractClassNameIfRequire(Node node, Node parent); /** * Function name used when exporting properties. * Signature: fn(object, publicName, symbol). * @return function name. */ public String getExportPropertyFunction(); /** * Function name used when exporting symbols. * Signature: fn(publicPath, object). * @return function name. */ public String getExportSymbolFunction(); /** * Checks if the given CALL node is forward-declaring any types, * and returns the name of the types if it is. */ public List<String> identifyTypeDeclarationCall(Node n); /** * Checks if the given ASSIGN node is a typedef, and returns the * name of the type if it is. */ public String identifyTypeDefAssign(Node n); /** * In many JS libraries, the function that produces inheritance also * adds properties to the superclass and/or subclass. */ public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type); /** * Function name for abstract methods. An abstract method can be assigned to * an interface method instead of an anonymous function in order to avoid * linter warnings produced by assigning a function without a return value * where a return value is expected. * @return function name. */ public String getAbstractMethodName(); /** * Checks if the given method defines a singleton getter, and if it does, * returns the name of the class with the singleton getter. By default, always * returns null. Meant to be overridden by subclasses. * * @param callNode A CALL node. */ public String getSingletonGetterClassName(Node callNode); /** * In many JS libraries, the function that adds a singleton getter to a class * adds properties to the class. */ public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType); public DelegateRelationship getDelegateRelationship(Node callNode); /** * In many JS libraries, the function that creates a delegate relationship * also adds properties to the deleg

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>JSType that) { boolean canAssign = true; for (JSType t : alternates) { if (t.isUnknownType()) { return true; } canAssign &= t.canAssignTo(that); } return canAssign; } @Override public boolean canBeCalled() { for (JSType t : alternates) { if (!t.canBeCalled()) { return false; } } return true; } @Override public JSType restrictByNotNullOrUndefined() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { restricted.addAlternate(t.restrictByNotNullOrUndefined()); } return restricted.build(); } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = null; for (JSType t : alternates) { TernaryValue test = t.testForEquality(that); if (result == null) { result = test; } else if (!result.equals(test)) { return UNKNOWN; } } return result; } /** * This predicate determines whether objects of this type can have the * {@code null} value, and therefore can appear in contexts where * {@code null} is expected. * * @return {@code true} for everything but {@code Number} and * {@code Boolean} types. */ @Override public boolean isNullable() { for (JSType t : alternates) { if (t.isNullable()) { return true; } } return false; } @Override public boolean isUnknownType() { for (JSType t : alternates) { if (t.isUnknownType()) { return true; } } return false; } @Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType()) { for (JSType alternate : alternates) { if (!alternate.isUnknownType() && that.isSubtype(alternate)) { return this; } } } return getLeastSupertype(this, that); } JSType meet(JSType that) { UnionTypeBuilder builder

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> = new UnionTypeBuilder(registry); for (JSType alternate : alternates) { if (alternate.isSubtype(that)) { builder.addAlternate(alternate); } } if (that instanceof UnionType) { for (JSType otherAlternate : ((UnionType) that).alternates) { if (otherAlternate.isSubtype(this)) { builder.addAlternate(otherAlternate); } } } else if (that.isSubtype(this)) { builder.addAlternate(that); } JSType result = builder.build(); if (!result.isNoType()) { return result; } else if (this.isObject() && that.isObject()) { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } else { return getNativeType(JSTypeNative.NO_TYPE); } } /** * Two union types are equal if they have the same number of alternates * and all alternates are equal. */ @Override public boolean equals(Object object) { if (object instanceof UnionType) { UnionType that = (UnionType) object; return alternates.equals(that.alternates); } else { return false; } } @Override public int hashCode() { return this.hashcode; } @Override public boolean isUnionType() { return true; } @Override public boolean isObject() { for (JSType alternate : alternates) { if (!alternate.isObject()) { return false; } } return true; } /** * A {@link UnionType} contains a given type (alternate) iff the member * vector contains it. Since the {@link #equals} method above conforms to * the necessary semantics for the collection, everything works out just * fine. * * @param alternate The alternate which might be in this union. * * @return {@code true} if the alternate is in the union */ public boolean contains(JSType alternate) { return alternates.contains(alternate); } /** * Returns a more restricted union type than {@code this} one, in which all * subtypes of {@code type} have been removed.<p> * * Examples:

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> } else { return getNativeType(JSTypeNative.NO_TYPE); } } public JSType caseAllType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseVoidType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseEnumElementType(EnumElementType type) { return type.getPrimitiveType().visit(this); } } NoObjectType(JSTypeRegistry registry) { super(registry, null, null, null, null, null, null, true, true); } @Override public JSType getReturnType() { return this; } @Override public ObjectType getInstanceType() { return this; } @Override public TernaryValue testForEquality(JSType that) { return that.isEmptyType() ? TernaryValue.TRUE : TernaryValue.UNKNOWN; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } else { return that.isObject() && !that.isNoType(); } } @Override public boolean isFunctionType() { return false; } @Override public boolean isNoObjectType() { return true; } @Override public JSType getLeastSupertype(JSType that) { return that.visit(leastSupertypeVisitor); } @Override public JSType getGreatestSubtype(JSType that) { return that.visit(greatestSubtypeVisitor); } @Override public ObjectType getImplicitPrototype() { return null; } @Override public String getReferenceName() { return null; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean equals(Object that) { return this == that; } @Override public int hashCode() { return System.identityHashCode(this); } @Override public int getPropertiesCount() { // Should never be called, returning the biggest number to highlight the // '

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>"; if (d == Double.NEGATIVE_INFINITY) return "-Infinity"; if (d == 0.0) return "0"; if ((base < 2) || (base > 36)) { throw Context.reportRuntimeError1( "msg.bad.radix", Integer.toString(base)); } if (base != 10) { return DToA.JS_dtobasestr(base, d); } else { StringBuffer result = new StringBuffer(); DToA.JS_dtostr(result, DToA.DTOSTR_STANDARD, 0, d); return result.toString(); } } /** * If str is a decimal presentation of Uint32 value, return it as long. * Othewise return -1L; */ public static long testUint32String(String str) { // The length of the decimal string representation of // UINT32_MAX_VALUE, 4294967296 final int MAX_VALUE_LENGTH = 10; int len = str.length(); if (1 <= len && len <= MAX_VALUE_LENGTH) { int c = str.charAt(0); c -= '0'; if (c == 0) { // Note that 00,01 etc. are not valid Uint32 presentations return (len == 1) ? 0L : -1L; } if (1 <= c && c <= 9) { long v = c; for (int i = 1; i != len; ++i) { c = str.charAt(i) - '0'; if (!(0 <= c && c <= 9)) { return -1; } v = 10 * v + c; } // Check for overflow if ((v >>> 32) == 0) { return v; } } } return -1; } static boolean isSpecialProperty(String s) { return s.equals("__proto__") || s.equals("__parent__"); } // ------------------ // Statements // ------------------ public static String getMessage0(String messageId) { return getMessage(messageId, null);

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Call(Node callNode) { return null; } @Override public boolean isSuperClassReference(String propertyName) { return false; } @Override public String extractClassNameIfProvide(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String extractClassNameIfRequire(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String getExportPropertyFunction() { return null; } @Override public String getExportSymbolFunction() { return null; } @Override public List<String> identifyTypeDeclarationCall(Node n) { return null; } @Override public String identifyTypeDefAssign(Node n) { return null; } @Override public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type) { // do nothing } @Override public String getAbstractMethodName() { return null; } @Override public String getSingletonGetterClassName(Node callNode) { return null; } @Override public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType) { // do nothing. } @Override public DelegateRelationship getDelegateRelationship(Node callNode) { return null; } @Override public void applyDelegateRelationship( ObjectType delegateSuperclass, ObjectType delegateBase, ObjectType delegator, FunctionType delegateProxy, FunctionType findDelegate) { // do nothing. } @Override public String getDelegateSuperclassName() { return null; } @Override public void defineDelegateProxyProperties( JSTypeRegistry registry, Scope scope, Map<ObjectType, ObjectType> delegateProxyMap) { // do nothing. } @Override public String getGlobalObject() { return "window"; } @Override public boolean isPropertyTestFunction(Node call) { return false; } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) { return null; } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.CALL: String className = findRequire ? codingConvention.extractClassNameIfRequire(n, parent) : codingConvention.extractClassNameIfProvide(n, parent); if (className != null) { types.add(className); } break; } } } /** * Gets the source line for the indicated line number. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Does not include the newline at the end * of the file. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public String getLine(int lineNumber) { return getSourceFile().getLine(lineNumber); } /** * Get a region around the indicated line number. The exact definition of a * region is implementation specific, but it must contain the line indicated * by the line number. A region must not start or end by a carriage return. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public Region getRegion(int lineNumber) { return getSourceFile().getRegion(lineNumber); } public String getCode() throws IOException { return getSourceFile().getCode(); } /** Returns the module to which the input belongs. */ public JSModule getModule() { return module; } /** Sets the module to which the input belongs. */ public void setModule(JSModule module) { // An input may only belong to one module. Preconditions.checkArgument( module == null || this.module == null || this.module == module); this.module = module; } public boolean isExtern() { return isExtern; } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Name The source file name * @param lineno Line number with source file, or -1 if unknown * @param charno Column number within line, or -1 for whole line. * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(String sourceName, int lineno, int charno, DiagnosticType type, String... arguments) { return new JSError(sourceName, lineno, charno, type, null, arguments); } /** * Creates a JSError at a given source location * * @param sourceName The source file name * @param lineno Line number with source file, or -1 if unknown * @param charno Column number within line, or -1 for whole line. * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(String sourceName, int lineno, int charno, CheckLevel level, DiagnosticType type, String... arguments) { return new JSError(sourceName, lineno, charno, type, level, arguments); } /** * Creates a JSError from a file and Node position. * * @param sourceName The source file name * @param n Determines the line and char position within the source file name * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(String sourceName, Node n, DiagnosticType type, String... arguments) { return new JSError(sourceName, n, type, arguments); } /** * Creates a JSError from a file and Node position. * * @param sourceName The source file name * @param n Determines the line and char position within the source file name * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(String sourceName, Node n, CheckLevel level, DiagnosticType type, String... arguments) { return new JSError(sourceName, n.getLineno(), n.getCharno(), type, level, arguments); } /** * Creates a JSError during NodeTraversal. * * @param t Determines source file name containing current script * @param

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> n Determines the line and char position within the source file name * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(NodeTraversal t, Node n, CheckLevel level, DiagnosticType type, String... arguments) { return new JSError(t.getSourceName(), n.getLineno(), n.getCharno(), type, level, arguments); } /** * Creates a JSError during NodeTraversal. * * @param t Determines source file name containing current script * @param n Determines the line and char position within the source file name * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public static JSError make(NodeTraversal t, Node n, DiagnosticType type, String... arguments) { return new JSError(t.getSourceName(), n, type, arguments); } // // JSError constructors // /** * Creates a JSError at a CheckLevel for a source file location. Package * private to avoid any entanglement with code outside of the compiler. * * This is a preferred internal constructor. */ private JSError(String sourceName, int lineno, int charno, DiagnosticType type, CheckLevel level, String... arguments) { this.type = type; this.description = type.format.format(arguments); this.lineNumber = lineno; this.charno = charno; this.sourceName = sourceName; this.level = level == null ? type.level : level; } /** * Creates a JSError for a source file location. Package private to avoid * any entanglement with code outside of the compiler. * * This is a preferred internal constructor. */ private JSError(String sourceName, Node node, DiagnosticType type, String... arguments) { this(sourceName, (node != null) ? node.getLineno() : -1, (node != null) ? node.getCharno() : -1, type, null, arguments); } public DiagnosticType getType() { return type; } /** * Format a message at the given level. * * @return the formatted message or {@code null

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>} */ public String format(CheckLevel level, MessageFormatter formatter) { switch (level) { case ERROR: return formatter.formatError(this); case WARNING: return formatter.formatWarning(this); default: return null; } } @Override public String toString() { // TODO(user): remove custom toString. return type.key + ". " + description + " at " + (sourceName != null && sourceName.length() > 0 ? sourceName : "(unknown source)") + " line " + (lineNumber != -1 ? String.valueOf(lineNumber) : "(unknown line)"); } /** * Get the character number. */ public int getCharno() { return charno; } @Override public boolean equals(Object o) { // Generated by Intellij IDEA if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } JSError jsError = (JSError) o; if (charno != jsError.charno) { return false; } if (lineNumber != jsError.lineNumber) { return false; } if (!description.equals(jsError.description)) { return false; } if (level != jsError.level) { return false; } if (sourceName != null ? !sourceName.equals(jsError.sourceName) : jsError.sourceName != null) { return false; } if (!type.equals(jsError.type)) { return false; } return true; } @Override public int hashCode() { // Generated by Intellij IDEA int result = type.hashCode(); result = 31 * result + description.hashCode(); result = 31 * result + (sourceName != null ? sourceName.hashCode() : 0); result = 31 * result + lineNumber; result = 31 * result + level.hashCode(); result = 31 * result + charno; return result; } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>. This method * effectively emulates the <code>Boolean()</code> JavaScript cast function. * * @throws IllegalArgumentException If {@code n} is not a literal value */ static boolean getBooleanValue(Node n) { switch (n.getType()) { case Token.STRING: return n.getString().length() > 0; case Token.NUMBER: return n.getDouble() != 0; case Token.NULL: case Token.FALSE: case Token.VOID: return false; case Token.NAME: String name = n.getString(); if ("undefined".equals(name) || "NaN".equals(name)) { // We assume here that programs don't change the value of the keyword // undefined to something other than the value undefined. return false; } else if ("Infinity".equals(name)) { return true; } break; case Token.TRUE: case Token.ARRAYLIT: case Token.OBJECTLIT: case Token.REGEXP: return true; } throw new IllegalArgumentException("Non-literal value: " + n); } /** * Gets the value of a node as a String, or null if it cannot be converted. * When it returns a non-null String, this method effectively emulates the * <code>String()</code> JavaScript cast function. */ static String getStringValue(Node n) { // TODO(user): Convert constant array, object, and regex literals as well. switch (n.getType()) { case Token.NAME: case Token.STRING: return n.getString(); case Token.NUMBER: double value = n.getDouble(); long longValue = (long) value; // Return "1" instead of "1.0" if (longValue == value) { return Long.toString(longValue); } else { return Double.toString(n.getDouble()); } case Token.FALSE: case Token.TRUE: case Token.NULL: return Node.tokenToName(n.getType()); case Token.VOID: return "undefined"; } return null; } /** * Gets the function's name. This method recognizes five forms: * <ul> * <li>{@code function name() ...}</li>

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> * <li>{@code var name = function() ...}</li> * <li>{@code qualified.name = function() ...}</li> * <li>{@code var name2 = function name1() ...}</li> * <li>{@code qualified.name2 = function name1() ...}</li> * </ul> * In two last cases with named anonymous functions, the second name is * returned (the variable of qualified name). * * @param n a node whose type is {@link Token#FUNCTION} * @param parent {@code n}'s parent (never {@code null}) * @return the function's name, or {@code null} if it has no name */ static String getFunctionName(Node n, Node parent) { String name = n.getFirstChild().getString(); switch (parent.getType()) { case Token.NAME: // var name = function() ... // var name2 = function name1() ... return parent.getString(); case Token.ASSIGN: // qualified.name = function() ... // qualified.name2 = function name1() ... return parent.getFirstChild().getQualifiedName(); default: // function name() ... return name != null && name.length() != 0 ? name : null; } } /** * Returns true if this is an immutable value. */ static boolean isImmutableValue(Node n) { switch (n.getType()) { case Token.STRING: case Token.NUMBER: case Token.NULL: case Token.TRUE: case Token.FALSE: case Token.VOID: return true; case Token.NEG: return isImmutableValue(n.getFirstChild()); case Token.NAME: String name = n.getString(); // We assume here that programs don't change the value of the keyword // undefined to something other than the value undefined. return "undefined".equals(name) || "Infinity".equals(name) || "NaN".equals(name); } return false; } /** * Returns true if this is a literal value. We define a literal value * as any node that evaluates to the same thing regardless of when or * where it is evaluated. So /xyz/ and [3, 5] are literals, but * function()

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> { return a; } is not. */ static boolean isLiteralValue(Node n) { // TODO(nicksantos): Refine this function to catch more literals. switch (n.getType()) { case Token.ARRAYLIT: case Token.OBJECTLIT: case Token.REGEXP: // Return true only if all children are const. for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { if (!isLiteralValue(child)) { return false; } } return true; default: return isImmutableValue(n); } } /** * Determines whether the given value may be assigned to a define. * * @param val The value being assigned. * @param defines The list of names of existing defines. */ static boolean isValidDefineValue(Node val, Set<String> defines) { switch (val.getType()) { case Token.STRING: case Token.NUMBER: case Token.TRUE: case Token.FALSE: return true; // Single operators are valid if the child is valid. case Token.BITAND: case Token.BITNOT: case Token.BITOR: case Token.BITXOR: case Token.NOT: case Token.NEG: return isValidDefineValue(val.getFirstChild(), defines); // Names are valid if and only if they are defines themselves. case Token.NAME: case Token.GETPROP: if (val.isQualifiedName()) { return defines.contains(val.getQualifiedName()); } } return false; } /** * Returns whether this a BLOCK node with no children. * * @param block The node. */ static boolean isEmptyBlock(Node block) { if (block.getType() != Token.BLOCK) { return false; } for (Node n = block.getFirstChild(); n != null; n = n.getNext()) { if (n.getType() != Token.EMPTY) { return false; } } return true; } /** * A "simple" operator is one whose children are expressions, * has no direct side-effects (unlike '+='), and has no * conditional aspects (unlike '||'). */ static boolean is

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>SimpleOperatorType(int type) { switch (type) { case Token.ADD: case Token.BITAND: case Token.BITNOT: case Token.BITOR: case Token.BITXOR: case Token.COMMA: case Token.DIV: case Token.EQ: case Token.GE: case Token.GETELEM: case Token.GETPROP: case Token.GT: case Token.INSTANCEOF: case Token.LE: case Token.LSH: case Token.LT: case Token.MOD: case Token.MUL: case Token.NE: case Token.NOT: case Token.RSH: case Token.SHEQ: case Token.SHNE: case Token.SUB: case Token.TYPEOF: case Token.VOID: case Token.POS: case Token.NEG: case Token.URSH: return true; default: return false; } } /** * Creates an EXPR_RESULT. * * @param child The expression itself. * @return Newly created EXPR node with the child as subexpression. */ public static Node newExpr(Node child) { return new Node(Token.EXPR_RESULT, child); } /** * Returns true if the node may create new mutable state, or change existing * state. * * @see <a href="http://www.xkcd.org/326/">XKCD Cartoon</a> */ static boolean mayEffectMutableState(Node n) { return checkForStateChangeHelper(n, true); } /** * Returns true if the node which may have side effects when executed. */ static boolean mayHaveSideEffects(Node n) { return checkForStateChangeHelper(n, false); } /** * Returns true if some node in n's subtree changes application state. * If {@code checkForNewObjects} is true, we assume that newly created * mutable objects (like object literals) change state. Otherwise, we assume * that they have no side effects. */ private static boolean checkForStateChangeHelper( Node n, boolean checkForNewObjects) { // Rather than id which ops may have side effects, id the ones // that we

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> know to be safe switch (n.getType()) { // other side-effect free statements and expressions case Token.AND: case Token.BLOCK: case Token.EXPR_RESULT: case Token.HOOK: case Token.IF: case Token.IN: case Token.LP: case Token.NUMBER: case Token.OR: case Token.THIS: case Token.TRUE: case Token.FALSE: case Token.NULL: case Token.STRING: case Token.SWITCH: case Token.TRY: case Token.EMPTY: break; // Throws are by definition side effects case Token.THROW: return true; case Token.OBJECTLIT: case Token.ARRAYLIT: case Token.REGEXP: if (checkForNewObjects) { return true; } break; case Token.VAR: // empty var statement (no declaration) case Token.NAME: // variable by itself if (n.getFirstChild() != null) return true; break; case Token.FUNCTION: // Anonymous functions don't have side-effects, but named ones // change the namespace. Therefore, we check if the function has // a name. Either way, we don't need to check the children, since // they aren't executed at declaration time. // return !isFunctionAnonymous(n); case Token.NEW: { if (checkForNewObjects) { return true; } // calls to constructors that have no side effects have the // no side effect property set. if (n.isNoSideEffectsCall()) { break; } // certain constructors are certified side effect free Node constructor = n.getFirstChild(); if (Token.NAME == constructor.getType()) { String className = constructor.getString(); if (CONSTRUCTORS_WITHOUT_SIDE_EFFECTS.contains(className)) { // loop below will see if the constructor parameters have // side-effects break; } } else { // the constructor could also be an expression like // new (useArray ? Object : Array)(); } } return true; case Token.CALL: // calls to functions that have no side effects have the no // side effect property set. if (n.isNoSide

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>EffectsCall()) { // loop below will see if the function parameters have // side-effects break; } return true; default: if (isSimpleOperatorType(n.getType())) break; if (isAssignmentOp(n)) { // Assignments will have side effects if // a) The RHS has side effects, or // b) The LHS has side effects, or // c) A name on the LHS will exist beyond the life of this statement. if (checkForStateChangeHelper( n.getFirstChild(), checkForNewObjects) || checkForStateChangeHelper( n.getLastChild(), checkForNewObjects)) { return true; } Node current = n.getFirstChild(); for (; current.getType() == Token.GETPROP || current.getType() == Token.GETELEM; current = current.getFirstChild()) { } return !(isLiteralValue(current) || current.getType() == Token.FUNCTION); } return true; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (checkForStateChangeHelper(c, checkForNewObjects)) { return true; } } return false; } /** * Do calls to this constructor have side effects? * * @param callNode - construtor call node */ static boolean constructorCallHasSideEffects(Node callNode) { Preconditions.checkArgument( callNode.getType() == Token.NEW, "Expected NEW node, got " + Token.name(callNode.getType())); if (callNode.isNoSideEffectsCall()) { return false; } Node nameNode = callNode.getFirstChild(); if (nameNode.getType() == Token.NAME && CONSTRUCTORS_WITHOUT_SIDE_EFFECTS.contains(nameNode.getString())) { return false; } return true; } /** * Returns true if calls to this function have side effects. * * @param callNode - function call node */ static boolean functionCallHasSideEffects(Node callNode) { Preconditions.checkArgument( callNode.getType() == Token.CALL, "Expected CALL node, got " + Token.name(callNode.getType())); if (

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>callNode.isNoSideEffectsCall()) { return false; } Node nameNode = callNode.getFirstChild(); // Built-in functions with no side effects. if (nameNode.getType() == Token.NAME) { String name = nameNode.getString(); if (name.equals("String")) { return false; } } // Functions in the "Math" namespace have no side effects. if (nameNode.getType() == Token.GETPROP && nameNode.getFirstChild().getType() == Token.NAME) { String namespaceName = nameNode.getFirstChild().getString(); if (namespaceName.equals("Math")) { return false; } } return true; } /** * Returns true if the current node's type implies side effects. * * This is a non-recursive version of the may have side effects * check; used to check wherever the current node's type is one of * the reason's why a subtree has side effects. */ static boolean nodeTypeMayHaveSideEffects(Node n) { if (NodeUtil.isAssignmentOp(n)) { return true; } switch(n.getType()) { case Token.CALL: case Token.DELPROP: case Token.NEW: case Token.DEC: case Token.INC: case Token.THROW: return true; case Token.NAME: // A variable definition. return n.hasChildren(); default: return false; } } /** * @return Whether the tree can be affected by side-effects or * has side-effects. */ static boolean canBeSideEffected(Node n) { Set<String> emptySet = Collections.emptySet(); return canBeSideEffected(n, emptySet); } /** * @param knownConstants A set of names known to be constant value at * node 'n' (such as locals that are last written before n can execute). * @return Whether the tree can be affected by side-effects or * has side-effects. */ static boolean canBeSideEffected(Node n, Set<String> knownConstants) { switch (n.getType()) { case Token.CALL: case Token.NEW: // Function calls or

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> constructor can reference changed values. // TODO(johnlenz): Add some mechanism for determining that functions // are unaffected by side effects. return true; case Token.NAME: // Non-constant names values may have been changed. return !NodeUtil.isConstantName(n) && !knownConstants.contains(n.getString()); // Properties on constant NAMEs can still be side-effected. case Token.GETPROP: case Token.GETELEM: return true; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (canBeSideEffected(c, knownConstants)) { return true; } } return false; } /* * 0 comma , * 1 assignment = += -= *= /= %= <<= >>= >>>= &= ^= |= * 2 conditional ?: * 3 logical-or || * 4 logical-and && * 5 bitwise-or | * 6 bitwise-xor ^ * 7 bitwise-and & * 8 equality == != * 9 relational < <= > >= * 10 bitwise shift << >> >>> * 11 addition/subtraction + - * 12 multiply/divide * / % * 13 negation/increment ! ~ - ++ -- * 14 call, member () [] . */ static int precedence(int type) { switch (type) { case Token.COMMA: return 0; case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case Token.ASSIGN_ADD: case Token.ASSIGN_SUB: case Token.ASSIGN_MUL: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: case Token.ASSIGN: return 1; case Token.HOOK: return 2; // ?: operator case Token.OR: return 3; case Token.AND: return 4; case Token.BITOR: return 5; case Token.BITXOR: return 6; case Token.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>.BITAND: return true; default: return false; } } static boolean isAssignmentOp(Node n) { switch (n.getType()){ case Token.ASSIGN: case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case Token.ASSIGN_ADD: case Token.ASSIGN_SUB: case Token.ASSIGN_MUL: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: return true; } return false; } static int getOpFromAssignmentOp(Node n) { switch (n.getType()){ case Token.ASSIGN_BITOR: return Token.BITOR; case Token.ASSIGN_BITXOR: return Token.BITXOR; case Token.ASSIGN_BITAND: return Token.BITAND; case Token.ASSIGN_LSH: return Token.LSH; case Token.ASSIGN_RSH: return Token.RSH; case Token.ASSIGN_URSH: return Token.URSH; case Token.ASSIGN_ADD: return Token.ADD; case Token.ASSIGN_SUB: return Token.SUB; case Token.ASSIGN_MUL: return Token.MUL; case Token.ASSIGN_DIV: return Token.DIV; case Token.ASSIGN_MOD: return Token.MOD; } throw new IllegalArgumentException("Not an assiment op"); } static boolean isExpressionNode(Node n) { return n.getType() == Token.EXPR_RESULT; } /** * Determines if the given node contains a function declaration. */ static boolean containsFunctionDeclaration(Node n) { return containsType(n, Token.FUNCTION); } /** * Returns true if the subtree contains references to 'this' keyword */ static boolean referencesThis(Node n) { return containsType(n, Token.THIS); } /** * Is this a GETPROP or GETELEM node? */ static boolean isGet(Node n) { return n.getType() == Token.GETPROP || n.getType() == Token.GETELEM; }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> /** * Is this a GETPROP node? */ static boolean isGetProp(Node n) { return n.getType() == Token.GETPROP; } /** * Is this a NAME node? */ static boolean isName(Node n) { return n.getType() == Token.NAME; } /** * Is this a NEW node? */ static boolean isNew(Node n) { return n.getType() == Token.NEW; } /** * Is this a VAR node? */ static boolean isVar(Node n) { return n.getType() == Token.VAR; } /** * Is this node the name of a variable being declared? * * @param n The node * @return True if {@code n} is NAME and {@code parent} is VAR */ static boolean isVarDeclaration(Node n) { // There is no need to verify that parent != null because a NAME node // always has a parent in a valid parse tree. return n.getType() == Token.NAME && n.getParent().getType() == Token.VAR; } /** * For an assignment or variable declaration get the assigned value. * @return The value node representing the new value. */ static Node getAssignedValue(Node n) { Preconditions.checkState(isName(n)); Node parent = n.getParent(); if (isVar(parent)) { return n.getFirstChild(); } else if (isAssign(parent) && parent.getFirstChild() == n) { return n.getNext(); } else { return null; } } /** * Is this a STRING node? */ static boolean isString(Node n) { return n.getType() == Token.STRING; } /** * Is this node an assignment expression statement? * * @param n The node * @return True if {@code n} is EXPR_RESULT and {@code n}'s * first child is ASSIGN */ static boolean isExprAssign(Node n) { return n.getType() == Token.EXPR_RESULT && n.getFirstChild().getType() == Token.ASSIGN; } /** * Is this an ASSIGN node? */ static boolean isAssign(Node

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> n) { return n.getType() == Token.ASSIGN; } /** * Is this node a call expression statement? * * @param n The node * @return True if {@code n} is EXPR_RESULT and {@code n}'s * first child is CALL */ static boolean isExprCall(Node n) { return n.getType() == Token.EXPR_RESULT && n.getFirstChild().getType() == Token.CALL; } /** * @return Whether the node represents a FOR-IN loop. */ static boolean isForIn(Node n) { return n.getType() == Token.FOR && n.getChildCount() == 3; } /** * Determines whether the given node is a FOR, DO, or WHILE node. */ static boolean isLoopStructure(Node n) { switch (n.getType()) { case Token.FOR: case Token.DO: case Token.WHILE: return true; default: return false; } } /** * @param n The node to inspect. * @return If the node, is a FOR, WHILE, or DO, it returns the node for * the code BLOCK, null otherwise. */ static Node getLoopCodeBlock(Node n) { switch (n.getType()) { case Token.FOR: case Token.WHILE: return n.getLastChild(); case Token.DO: return n.getFirstChild(); default: return null; } } /** * Determines whether the given node is a FOR, DO, WHILE, WITH, or IF node. */ static boolean isControlStructure(Node n) { switch (n.getType()) { case Token.FOR: case Token.DO: case Token.WHILE: case Token.WITH: case Token.IF: case Token.LABEL: case Token.TRY: case Token.CATCH: case Token.SWITCH: case Token.CASE: case Token.DEFAULT: return true; default: return false; } } /** * Determines whether the given node is code node for FOR, DO, * WHILE, WITH, or IF node. */ static boolean isControlStructureCodeBlock(

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Node parent, Node n) { switch (parent.getType()) { case Token.FOR: case Token.WHILE: case Token.LABEL: case Token.WITH: return parent.getLastChild() == n; case Token.DO: return parent.getFirstChild() == n; case Token.IF: return parent.getFirstChild() != n; case Token.TRY: return parent.getFirstChild() == n || parent.getLastChild() == n; case Token.CATCH: return parent.getLastChild() == n; case Token.SWITCH: case Token.CASE: return parent.getFirstChild() != n; case Token.DEFAULT: return true; default: Preconditions.checkState(isControlStructure(parent)); return false; } } /** * Gets the condition of an ON_TRUE / ON_FALSE CFG edge. * @param n a node with an outgoing conditional CFG edge * @return the condition node or null if the condition is not obviously a node */ static Node getConditionExpression(Node n) { switch (n.getType()) { case Token.IF: case Token.WHILE: return n.getFirstChild(); case Token.DO: return n.getLastChild(); case Token.FOR: switch (n.getChildCount()) { case 3: return null; case 4: return n.getFirstChild().getNext(); } throw new IllegalArgumentException("malformed 'for' statement " + n); case Token.CASE: return null; } throw new IllegalArgumentException(n + " does not have a condition."); } /** * @return Whether the node is of a type that contain other statements. */ static boolean isStatementBlock(Node n) { return n.getType() == Token.SCRIPT || n.getType() == Token.BLOCK; } /** * @return Whether the node is used as a statement. */ static boolean isStatement(Node n) { Node parent = n.getParent(); // It is not possible to determine definitely if a node is a statement // or not if it is not part of the AST. A FUNCTION node, for instance, // is either part of an expression (as a anonymous function) or as // a statement.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> Preconditions.checkState(parent != null); switch (parent.getType()) { case Token.SCRIPT: case Token.BLOCK: case Token.LABEL: return true; default: return false; } } /** Whether the node is part of a switch statement. */ static boolean isSwitchCase(Node n) { return n.getType() == Token.CASE || n.getType() == Token.DEFAULT; } /** @return Whether the node is a label name. */ static boolean isLabelName(Node n) { if (n != null && n.getType() == Token.NAME) { Node parent = n.getParent(); switch (parent.getType()) { case Token.LABEL: case Token.BREAK: case Token.CONTINUE: if (n == parent.getFirstChild()) { return true; } } } return false; } /** Whether the child node is the FINALLY block of a try. */ static boolean isTryFinallyNode(Node parent, Node child) { return parent.getType() == Token.TRY && parent.getChildCount() == 3 && child == parent.getLastChild(); } /** Safely remove children while maintaining a valid node structure. */ static void removeChild(Node parent, Node node) { // Node parent = node.getParent(); if (isStatementBlock(parent) || isSwitchCase(node) || isTryFinallyNode(parent, node)) { // A statement in a block can simply be removed. parent.removeChild(node); } else if (parent.getType() == Token.VAR) { if (parent.hasMoreThanOneChild()) { parent.removeChild(node); } else { // Remove the node from the parent, so it can be reused. parent.removeChild(node); // This would leave an empty VAR, remove the VAR itself. removeChild(parent.getParent(), parent); } } else if (node.getType() == Token.BLOCK) { // Simply empty the block. This maintains source location and // "synthetic"-ness. node.detachChildren(); } else if (parent.getType() == Token.LABEL && node == parent.getLastChild()) { // Remove the node from the parent, so it can be reused.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> parent.removeChild(node); // A LABEL without children can not be referred to, remove it. removeChild(parent.getParent(), parent); } else if (parent.getType() == Token.FOR && parent.getChildCount() == 4) { // Only Token.FOR can have an Token.EMPTY other control structure // need something for the condition. Others need to be replaced // or the structure removed. parent.replaceChild(node, new Node(Token.EMPTY)); } else { throw new IllegalStateException("Invalid attempt to remove node: " + node.toString() + " of "+ parent.toString()); } } /** * Merge a block with its parent block. * @return Whether the block was removed. */ static boolean tryMergeBlock(Node block) { Preconditions.checkState(block.getType() == Token.BLOCK); Node parent = block.getParent(); // Try to remove the block if its parent is a block/script or if its // parent is label and it has exactly one child. if (NodeUtil.isStatementBlock(parent)) { Node previous = block; while (block.hasChildren()) { Node child = block.removeFirstChild(); parent.addChildAfter(child, previous); previous = child; } parent.removeChild(block); return true; } else if (parent.getType() == Token.LABEL && block.hasOneChild()) { parent.replaceChild(block, block.removeFirstChild()); return true; } else { return false; } } /** * Is this a CALL node? */ static boolean isCall(Node n) { return n.getType() == Token.CALL; } /** * Is this a FUNCTION node? */ static boolean isFunction(Node n) { return n.getType() == Token.FUNCTION; } /** * Return a BLOCK node for the given FUNCTION node. */ static Node getFunctionBody(Node fn) { Preconditions.checkArgument(isFunction(fn)); return fn.getLastChild(); } /** * Is this a THIS node? */ static boolean isThis(Node node) { return node.getType() == Token.THIS; } /** * Is this node or any of its children

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> a CALL? */ static boolean containsCall(Node n) { return containsType(n, Token.CALL); } /** * Is this node a function declaration? A function declaration is a function * that has a name that is added to the current scope (i.e. a function that * is not anonymous; see {@link #isFunctionAnonymous}). */ static boolean isFunctionDeclaration(Node n) { return n.getType() == Token.FUNCTION && !isFunctionAnonymous(n); } /** * Is this node a hoisted function declaration? A function declaration in the * scope root is hoisted to the top of the scope. * See {@link #isFunctionDeclaration}). */ static boolean isHoistedFunctionDeclaration(Node n) { return NodeUtil.isFunctionDeclaration(n) && (n.getParent().getType() == Token.SCRIPT || n.getParent().getParent().getType() == Token.FUNCTION); } /** * Is this node an anonymous function? An anonymous function is one that has * either no name or a name that is not added to the current scope (see * {@link #isFunctionAnonymous}). */ static boolean isAnonymousFunction(Node n) { return n.getType() == Token.FUNCTION && isFunctionAnonymous(n); } /** * Is a FUNCTION node an anonymous function? An anonymous function is one that * has either no name or a name that is not added to the current scope. * * <p>Some examples of anonymous functions: * <pre> * function () {} * (function f() {})() * [ function f() {} ] * var f = function f() {}; * for (function f() {};;) {} * </pre> * * <p>Some examples of functions that are <em>not</em> anonymous: * <pre> * function f() {} * if (x); else function f() {} * for (;;) { function f() {} } * </pre> * * @param n A FUNCTION node * @return Whether n is an anonymous function */ static boolean isFunctionAnonymous(Node n) { return !isStatement(n); } /** * Determines if a function takes a variable number of arguments by * looking for references to the "arguments"

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> var_args object. */ static boolean isVarArgsFunction(Node function) { Preconditions.checkArgument(isFunction(function)); return NodeUtil.isNameReferenced( function.getLastChild(), "arguments", Predicates.<Node>not(new NodeUtil.MatchNodeType(Token.FUNCTION))); } /** * @return Whether node is a call to methodName. * a.f(...) * a['f'](...) */ static boolean isObjectCallMethod(Node callNode, String methodName) { if (callNode.getType() == Token.CALL) { Node functionIndentifyingExpression = callNode.getFirstChild(); if (NodeUtil.isGet(functionIndentifyingExpression)) { Node last = functionIndentifyingExpression.getLastChild(); if (last != null && last.getType() == Token.STRING) { String propName = last.getString(); return (propName.equals(methodName)); } } } return false; } /** * @return Whether the callNode represents an expression in the form of: * x.call(...) * x['call'](...) */ static boolean isFunctionObjectCall(Node callNode) { return isObjectCallMethod(callNode, "call"); } /** * @return Whether the callNode represents an expression in the form of: * x.apply(...) * x['apply'](...) */ static boolean isFunctionObjectApply(Node callNode) { return isObjectCallMethod(callNode, "apply"); } /** * @return Whether the callNode represents an expression in the form of: * x.call(...) * x['call'](...) * where x is a NAME node. */ static boolean isSimpleFunctionObjectCall(Node callNode) { if (isFunctionObjectCall(callNode)) { if (callNode.getFirstChild().getFirstChild().getType() == Token.NAME) { return true; } } return false; } /** * Determines whether this node is strictly on the left hand side of an assign * or var initialization. Notably, this does not include all L-values, only * statements where the node is used only as an L-value. * * @param n The node

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> * @param parent Parent of the node * @return True if n is the left hand of an assign */ static boolean isLhs(Node n, Node parent) { return (parent.getType() == Token.ASSIGN && parent.getFirstChild() == n) || parent.getType() == Token.VAR; } /** * Determines whether a node represents an object literal key * (e.g. key1 in {key1: value1, key2: value2}). * * @param node A node * @param parent The node's parent */ static boolean isObjectLitKey(Node node, Node parent) { if (node.getType() == Token.STRING && parent.getType() == Token.OBJECTLIT) { int index = 0; for (Node current = parent.getFirstChild(); current != null; current = current.getNext()) { if (current == node) { return index % 2 == 0; } index++; } } return false; } /** * Converts an operator's token value (see {@link Token}) to a string * representation. * * @param operator the operator's token value to convert * @return the string representation or {@code null} if the token value is * not an operator */ static String opToStr(int operator) { switch (operator) { case Token.BITOR: return "|"; case Token.OR: return "||"; case Token.BITXOR: return "^"; case Token.AND: return "&&"; case Token.BITAND: return "&"; case Token.SHEQ: return "==="; case Token.EQ: return "=="; case Token.NOT: return "!"; case Token.NE: return "!="; case Token.SHNE: return "!=="; case Token.LSH: return "<<"; case Token.IN: return "in"; case Token.LE: return "<="; case Token.LT: return "<"; case Token.URSH: return ">>>"; case Token.RSH: return ">>"; case Token.GE: return ">="; case Token.GT: return ">"; case Token.MUL: return "*"; case Token.DIV: return "/";

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> * @return true if n or any of its children are of the specified type */ static boolean containsType(Node node, int type) { return containsType(node, type, Predicates.<Node>alwaysTrue()); } /** * Given a node tree, finds all the VAR declarations in that tree that are * not in an inner scope. Then adds a new VAR node at the top of the current * scope that redeclares them, if necessary. */ static void redeclareVarsInsideBranch(Node branch) { Collection<Node> vars = getVarsDeclaredInBranch(branch); if (vars.isEmpty()) { return; } Node parent = getAddingRoot(branch); for (Node nameNode : vars) { Node var = new Node( Token.VAR, Node.newString(Token.NAME, nameNode.getString())); copyNameAnnotations(nameNode, var.getFirstChild()); parent.addChildToFront(var); } } /** * Copy any annotations that follow a named value. * @param source * @param destination */ static void copyNameAnnotations(Node source, Node destination) { if (source.getBooleanProp(Node.IS_CONSTANT_NAME)) { destination.putBooleanProp(Node.IS_CONSTANT_NAME, true); } } /** * Gets a Node at the top of the current scope where we can add new var * declarations as children. */ private static Node getAddingRoot(Node n) { Node addingRoot = null; Node ancestor = n; while (null != (ancestor = ancestor.getParent())) { int type = ancestor.getType(); if (type == Token.SCRIPT) { addingRoot = ancestor; break; } else if (type == Token.FUNCTION) { addingRoot = ancestor.getLastChild(); break; } } // make sure that the adding root looks ok Preconditions.checkState(addingRoot.getType() == Token.BLOCK || addingRoot.getType() == Token.SCRIPT); Preconditions.checkState(addingRoot.getFirstChild() == null || addingRoot.getFirstChild().getType() != Token.SCRIPT); return addingRoot; } /** Creates function name(params_0, ..., params_n) { body }. */ public static

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> node. Used for debugging information. * * @return A NAME or GETPROP node */ static Node newQualifiedNameNode(String name, Node basisNode, String originalName) { Node node = newQualifiedNameNode(name, -1, -1); setDebugInformation(node, basisNode, originalName); return node; } /** * Sets the debug information (source file info and orignal name) * on the given node. * * @param node The node on which to set the debug information. * @param basisNode The basis node from which to copy the source file info. * @param originalName The original name of the node. */ static void setDebugInformation(Node node, Node basisNode, String originalName) { node.copyInformationFromForTree(basisNode); node.putProp(Node.ORIGINALNAME_PROP, originalName); } /** * Creates a new node representing an *existing* name, copying over the source * location information from the basis node. * * @param name The name for the new NAME node. * @param basisNode The node that represents the name as currently found in * the AST. * * @return The node created. */ static Node newName(String name, Node basisNode) { Node nameNode = Node.newString(Token.NAME, name); nameNode.copyInformationFrom(basisNode); return nameNode; } /** * Creates a new node representing an *existing* name, copying over the source * location information from the basis node and assigning the given original * name to the node. * * @param name The name for the new NAME node. * @param basisNode The node that represents the name as currently found in * the AST. * @param originalName The original name of the item being represented by the * NAME node. Used for debugging information. * * @return The node created. */ static Node newName(String name, Node basisNode, String originalName) { Node nameNode = newName(name, basisNode); nameNode.putProp(Node.ORIGINALNAME_PROP, originalName); return nameNode; } /** Test if all characters in the string are in the Basic Lat

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>in (aka ASCII) * character set - that they have UTF-16 values equal to or below 0x7f. * This check can find which identifiers with Unicode characters need to be * escaped in order to allow resulting files to be processed by non-Unicode * aware UNIX tools and editors. * * * See http://en.wikipedia.org/wiki/Latin_characters_in_Unicode * for more on Basic Latin. * * @param s The string to be checked for ASCII-goodness. * * @return True if all characters in the string are in Basic Latin set. */ static boolean isLatin(String s) { char LARGEST_BASIC_LATIN = 0x7f; int len = s.length(); for (int index = 0; index < len; index++) { char c = s.charAt(index); if (c > LARGEST_BASIC_LATIN) { return false; } } return true; } /** * Determines whether the given name can appear on the right side of * the dot operator. Many properties (like reserved words) cannot. */ static boolean isValidPropertyName(String name) { return TokenStream.isJSIdentifier(name) && !TokenStream.isKeyword(name) && // no Unicode escaped characters - some browsers are less tolerant // of Unicode characters that might be valid according to the // language spec. // Note that by this point, unicode escapes have been converted // to UTF-16 characters, so we're only searching for character // values, not escapes. NodeUtil.isLatin(name); } private static class VarCollector implements Visitor { final Map<String, Node> vars = Maps.newLinkedHashMap(); public void visit(Node n) { if (n.getType() == Token.NAME) { Node parent = n.getParent(); if (parent != null && parent.getType() == Token.VAR) { String name = n.getString(); if (!vars.containsKey(name)) { vars.put(name, n); } } } } } /** * Retrieves vars declared in the current node tree, excluding descent scopes. */ public static Collection<Node

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>> getVarsDeclaredInBranch(Node root) { VarCollector collector = new VarCollector(); visitPreOrder( root, collector, Predicates.<Node>not(new NodeUtil.MatchNodeType(Token.FUNCTION))); return collector.vars.values(); } /** * @return {@code true} if the node an assignment to a prototype property of * some constructor. */ static boolean isPrototypePropertyDeclaration(Node n) { if (!NodeUtil.isExprAssign(n)) { return false; } return isPrototypeProperty(n.getFirstChild().getFirstChild()); } static boolean isPrototypeProperty(Node n) { String lhsString = n.getQualifiedName(); if (lhsString == null) { return false; } int prototypeIdx = lhsString.indexOf(".prototype."); return prototypeIdx != -1; } /** * @return The class name part of a qualified prototype name. */ static Node getPrototypeClassName(Node qName) { Node cur = qName; while (isGetProp(cur)) { if (cur.getLastChild().getString().equals("prototype")) { return cur.getFirstChild(); } else { cur = cur.getFirstChild(); } } return null; } /** * @return The string property name part of a qualified prototype name. */ static String getPrototypePropertyName(Node qName) { String qNameStr = qName.getQualifiedName(); int prototypeIdx = qNameStr.lastIndexOf(".prototype."); int memberIndex = prototypeIdx + ".prototype".length() + 1; return qNameStr.substring(memberIndex); } /** * Create a node for an empty result expression: * "void 0" */ static Node newUndefinedNode() { // TODO(johnlenz): Why this instead of the more common "undefined"? return new Node(Token.VOID, Node.newNumber(0)); } /** * Create a VAR node containing the given name and initial value expression. */ static Node newVarNode(String name, Node value) { Node nodeName = Node.newString(Token.NAME, name); if (value != null) { nodeName.addChildrenToBack(value); } Node var =

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> new Node(Token.VAR, nodeName); return var; } /** * A predicate for matching name nodes with the specified node. */ private static class MatchNameNode implements Predicate<Node>{ final String name; MatchNameNode(String name){ this.name = name; } public boolean apply(Node n) { return n.getType() == Token.NAME && n.getString().equals(name); } } /** * A predicate for matching nodes with the specified type. */ static class MatchNodeType implements Predicate<Node>{ final int type; MatchNodeType(int type){ this.type = type; } public boolean apply(Node n) { return n.getType() == type; } } /** * Whether a Node type is within the node tree. */ static boolean isNodeTypeReferenced(Node node, int type) { return isNodeTypeReferenced(node, type, Predicates.<Node>alwaysTrue()); } /** * Whether a Node type is within the node tree. */ static boolean isNodeTypeReferenced( Node node, int type, Predicate<Node> traverseChildrenPred) { return has(node, new MatchNodeType(type), traverseChildrenPred); } /** * Finds the number of times a type is referenced within the node tree. */ static int getNodeTypeReferenceCount(Node node, int type) { return getCount(node, new MatchNodeType(type)); } /** * Whether a simple name is referenced within the node tree. */ static boolean isNameReferenced(Node node, String name, Predicate<Node> traverseChildrenPred) { return has(node, new MatchNameNode(name), traverseChildrenPred); } /** * Whether a simple name is referenced within the node tree. */ static boolean isNameReferenced(Node node, String name) { return isNameReferenced(node, name, Predicates.<Node>alwaysTrue()); } /** * Finds the number of times a simple name is referenced within the node tree. */ static int getNameReferenceCount(Node node, String name) { return getCount(node, new MatchNameNode(name) ); } /** * @return Whether the predicate is true for the node or any of its children.

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> */ static boolean has(Node node, Predicate<Node> pred, Predicate<Node> traverseChildrenPred) { if (pred.apply(node)) { return true; } if (!traverseChildrenPred.apply(node)) { return false; } for (Node c = node.getFirstChild(); c != null; c = c.getNext()) { if (has(c, pred, traverseChildrenPred)) { return true; } } return false; } /** * @return The number of times the the predicate is true for the node * or any of its children. */ static int getCount(Node n, Predicate<Node> pred) { int total = 0; if (pred.apply(n)) { total++; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { total += getCount(c, pred); } return total; } /** * Interface for use with the visit method. * @see #visit */ static interface Visitor { void visit(Node node); } /** * A pre-order traversal, calling Vistor.visit for each child matching * the predicate. */ static void visitPreOrder(Node node, Visitor vistor, Predicate<Node> traverseChildrenPred) { vistor.visit(node); if (traverseChildrenPred.apply(node)) { for (Node c = node.getFirstChild(); c != null; c = c.getNext()) { visitPreOrder(c, vistor, traverseChildrenPred); } } } /** * A post-order traversal, calling Vistor.visit for each child matching * the predicate. */ static void visitPostOrder(Node node, Visitor vistor, Predicate<Node> traverseChildrenPred) { if (traverseChildrenPred.apply(node)) { for (Node c = node.getFirstChild(); c != null; c = c.getNext()) { visitPostOrder(c, vistor, traverseChildrenPred); } } vistor.visit(node); } /** * @return Whether a TRY node has a finally block. */ static boolean hasFinally(Node n) { Preconditions.checkArgument

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>(n.getType() == Token.TRY); return n.getChildCount() == 3; } /** * @return The BLOCK node containing the CATCH node (if any) * of a TRY. */ static Node getCatchBlock(Node n) { Preconditions.checkArgument(n.getType() == Token.TRY); return n.getFirstChild().getNext(); } /** * @return Whether BLOCK (from a TRY node) contains a CATCH. * @see NodeUtil#getCatchBlock */ static boolean hasCatchHandler(Node n) { Preconditions.checkArgument(n.getType() == Token.BLOCK); return n.hasChildren() && n.getFirstChild().getType() == Token.CATCH; } /** * @param fnNode The function. * @return The Node containing the Function parameters. */ static Node getFnParameters(Node fnNode) { // Function NODE: [ FUNCTION -> NAME, LP -> ARG1, ARG2, ... ] Preconditions.checkArgument(fnNode.getType() == Token.FUNCTION); return fnNode.getFirstChild().getNext(); } /** * Returns true if a name node represents a constant variable. * * <p>Determining whether a variable is constant has three steps: * <ol> * <li>In CodingConventionAnnotator, any name that matches the * {@link CodingConvention#isConstant(String)} is annotated with an * IS_CONSTANT_NAME property. * <li>The normalize pass renames any variable with the IS_CONSTANT_NAME * annotation and that is initialized to a constant value with * a variable name inlucding $$constant. * <li>Return true here if the variable includes $$constant in its name. * </ol> * * @param node A NAME or STRING node * @return True if the variable is constant */ static boolean isConstantName(Node node) { return node.getBooleanProp(Node.IS_CONSTANT_NAME); } /** * @param nameNode A name node * @return The JSDocInfo for the name node */ static JSDocInfo getInfoForNameNode(Node nameNode) { JSDocInfo info = null; Node parent = null; if

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> (nameNode != null) { info = nameNode.getJSDocInfo(); parent = nameNode.getParent(); } if (info == null && parent != null && ((parent.getType() == Token.VAR && parent.hasOneChild()) || parent.getType() == Token.FUNCTION)) { info = parent.getJSDocInfo(); } return info; } /** * @param n The node. * @return The source name property on the node or its ancestors. */ static String getSourceName(Node n) { String sourceName = null; while (sourceName == null && n != null) { sourceName = (String) n.getProp(Node.SOURCENAME_PROP); n = n.getParent(); } return sourceName; } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> Construct a tracer whose type is based on the short name of the object * @param object Object to use as type name * @param comment A comment * @return new Tracer. */ static Tracer shortName(Object object, String comment) { if (object == null) { return new Tracer(comment); } return new Tracer(object.getClass().getSimpleName(), comment); } /** * Converts 'v' to a string and pads it with up to 16 spaces for * improved alignment. * @param v The value to convert. * @param digits_column_width The desired with of the string. */ private static String longToPaddedString(long v, int digits_column_width) { int digit_width = numDigits(v); StringBuilder sb = new StringBuilder(); appendSpaces(sb, digits_column_width - digit_width); sb.append(v); return sb.toString(); } /** * Gets the number of digits in an integer when printed in base 10. Assumes * a positive integer. * @param n The value. * @return The number of digits in the string. */ private static int numDigits(long n) { int i = 0; do { i++; n = n / 10; } while (n > 0); return i; } /** * Gets a string of spaces of the length specified. * @param sb The string builder to append to. * @param numSpaces The number of spaces in the string. */ @VisibleForTesting static void appendSpaces(StringBuilder sb, int numSpaces) { if (numSpaces > 16) { logger.warning("Tracer.appendSpaces called with large numSpaces"); // Avoid long loop in case some bug in the caller numSpaces = 16; } while (numSpaces >= 5) { sb.append(" "); numSpaces -= 5; } // We know it's less than 5 now switch (numSpaces) { case 1: sb.append(" "); break; case 2: sb.append(" "); break; case 3: sb.append("

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> path through // the code identical to how it's been for years. this.outputCharsetEncoder = null; } else { this.outputCharsetEncoder = outputCharset.newEncoder(); } } CodeGenerator(CodeConsumer consumer, Charset outputCharset) { this(consumer, outputCharset, true); } CodeGenerator(CodeConsumer consumer) { this(consumer, null, false); } void add(String str) { cc.add(str); } private void addIdentifier(String identifier) { cc.addIdentifier(identifierEscape(identifier)); } void add(Node n) { add(n, Context.OTHER); } void add(Node n, Context context) { if (!cc.continueProcessing()) { return; } int type = n.getType(); String opstr = NodeUtil.opToStr(type); int childCount = n.getChildCount(); Node first = n.getFirstChild(); Node last = n.getLastChild(); // Handle all binary operators if (opstr != null && first != last) { Preconditions.checkState(childCount == 2); int p = NodeUtil.precedence(type); addLeftExpr(first, p, context); cc.addOp(opstr, true); // For right-hand-side of operations, only pass context if it's // the IN_FOR_INIT_CLAUSE one. Context rhsContext = getContextForNoInOperator(context); // Handle associativity. // e.g. if the parse tree is a * (b * c), // we can simply generate a * b * c. if (last.getType() == type && NodeUtil.isAssociative(type)) { addExpr(last, p, rhsContext); } else if (NodeUtil.isAssignmentOp(n) && NodeUtil.isAssignmentOp(last)) { // Assignments are the only right-associative binary operators addExpr(last, p, rhsContext); } else { addExpr(last, p + 1, rhsContext); } return; } cc.startSourceMapping(n); switch (type) { case Token.TRY: { Preconditions.checkState(first.getNext().getType() ==

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> Token.BLOCK && first.getNext().getChildCount() <= 1); Preconditions.checkState(childCount >= 2 && childCount <= 3); add("try"); add(first, Context.PRESERVE_BLOCK); // second child contains the catch block, or nothing if there // isn't a catch block Node catchblock = first.getNext().getFirstChild(); if (catchblock != null) { add(catchblock); } if (childCount == 3) { add("finally"); add(last, Context.PRESERVE_BLOCK); } break; } case Token.CATCH: Preconditions.checkState(childCount == 3); if (first.getNext().getType() != Token.EMPTY) { throw new Error("Catch conditions not suppored because I think" + " that it may be a netscape only feature."); } add("catch("); add(first); add(")"); add(last, Context.PRESERVE_BLOCK); break; case Token.THROW: Preconditions.checkState(childCount == 1); add("throw"); add(first); // Must have a ';' after a throw statement, otherwise safari can't // parse this. cc.endStatement(true); break; case Token.RETURN: add("return"); if (childCount == 1) { add(first); } else { Preconditions.checkState(childCount == 0); } cc.endStatement(); break; case Token.VAR: if (first != null) { add("var "); addList(first, false, getContextForNoInOperator(context)); } break; case Token.NAME: if (first == null || first.getType() == Token.EMPTY) { addIdentifier(n.getString()); } else { Preconditions.checkState(childCount == 1); addIdentifier(n.getString()); cc.addOp("=", true); if (first.getType() == Token.COMMA) { addExpr(first, NodeUtil.precedence(Token.ASSIGN)); } else { // Add expression, consider nearby code at lowest level of // precedence. addExpr(first, 0, getContextForNoInOperator

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>(context)); } } break; case Token.ARRAYLIT: add("["); addList(first, (int[]) n.getProp(Node.SKIP_INDEXES_PROP)); add("]"); break; case Token.LP: add("("); addList(first); add(")"); break; case Token.COMMA: addList(first, false, context); break; case Token.NUMBER: Preconditions.checkState(childCount == 0); cc.addNumber(n.getDouble()); break; case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: case Token.NEG: { // All of these unary operators are right-associative Preconditions.checkState(childCount == 1); cc.addOp(NodeUtil.opToStrNoFail(type), false); addExpr(first, NodeUtil.precedence(type)); break; } case Token.HOOK: { Preconditions.checkState(childCount == 3); int p = NodeUtil.precedence(type); addLeftExpr(first, p + 1, context); cc.addOp("?", true); addExpr(first.getNext(), p); cc.addOp(":", true); addExpr(last, p); break; } case Token.REGEXP: if (first.getType() != Token.STRING || last.getType() != Token.STRING) { throw new Error("Expected children to be strings"); } String regexp = regexpEscape(first.getString(), outputCharsetEncoder); // I only use one .add because whitespace matters if (childCount == 2) { add(regexp + last.getString()); } else { Preconditions.checkState(childCount == 1); add(regexp); } break; case Token.GET_REF: add(first); break; case Token.REF_SPECIAL: Preconditions.checkState(childCount == 1); add(first); add("."); add((String) n.getProp(Node.NAME_PROP)); break; case Token.FUNCTION: Preconditions.checkState(childCount == 3);

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> boolean funcNeedsParens = (context == Context.START_OF_EXPR); if (funcNeedsParens) { add("("); } add("function"); add(first); add(first.getNext()); add(last, Context.PRESERVE_BLOCK); cc.endFunction(context == Context.STATEMENT); if (funcNeedsParens) { add(")"); } break; case Token.SCRIPT: case Token.BLOCK: { boolean stripBlock = n.isSyntheticBlock() || ((context != Context.PRESERVE_BLOCK) && (n.getChildCount() < 2)); if (!stripBlock) { cc.beginBlock(); } for (Node c = first; c != null; c = c.getNext()) { add(c, Context.STATEMENT); // VAR doesn't include ';' since it gets used in expressions if (c.getType() == Token.VAR) { cc.endStatement(); } if (c.getType() == Token.FUNCTION) { cc.maybeLineBreak(); } // Prefer to break lines in between top-level statements // because top level statements are more homogeneous. if (type == Token.SCRIPT) { cc.notePreferredLineBreak(); } } if (!stripBlock) { cc.endBlock(context == Context.STATEMENT); } break; } case Token.FOR: if (childCount == 4) { add("for("); if (first.getType() == Token.VAR) { add(first, Context.IN_FOR_INIT_CLAUSE); } else { addExpr(first, 0, Context.IN_FOR_INIT_CLAUSE); } add(";"); add(first.getNext()); add(";"); add(first.getNext().getNext()); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } else { Preconditions.checkState(childCount == 3); add("for("); add(first); add("in"); add(first.getNext()); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } break

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>; case Token.DO: Preconditions.checkState(childCount == 2); add("do"); addNonEmptyExpression(first, Context.OTHER, false); add("while("); add(last); add(")"); cc.endStatement(); break; case Token.WHILE: Preconditions.checkState(childCount == 2); add("while("); add(first); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); break; case Token.EMPTY: Preconditions.checkState(childCount == 0); break; case Token.GETPROP: { Preconditions.checkState(childCount == 2); Preconditions.checkState(last.getType() == Token.STRING); boolean needsParens = (first.getType() == Token.NUMBER); if (needsParens) { add("("); } addLeftExpr(first, NodeUtil.precedence(type), context); if (needsParens) { add(")"); } add("."); addIdentifier(last.getString()); break; } case Token.GETELEM: Preconditions.checkState(childCount == 2); addLeftExpr(first, NodeUtil.precedence(type), context); add("["); add(first.getNext()); add("]"); break; case Token.WITH: Preconditions.checkState(childCount == 2); add("with("); add(first); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); break; case Token.INC: case Token.DEC: { Preconditions.checkState(childCount == 1); String o = type == Token.INC ? "++" : "--"; int postProp = n.getIntProp(Node.INCRDECR_PROP, 0); // A non-zero post-prop value indicates a post inc/dec, default of zero // is a pre-inc/dec. if (postProp != 0) { addLeftExpr(first, NodeUtil.precedence(type), context); cc.addOp(o, false); } else { cc.addOp(o, false);

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> add(first); } break; } case Token.CALL: // If the left hand side of the call is a direct reference to eval, // then it must have a DIRECT_EVAL annotation. If it does not, then // that means it was originally an indirect call to eval, and that // indirectness must be preserved. if (first.getType() == Token.NAME && "eval".equals(first.getString()) && !first.getBooleanProp(Node.DIRECT_EVAL)) { add("(0,eval)"); } else { addLeftExpr(first, NodeUtil.precedence(type), context); } add("("); addList(first.getNext()); add(")"); break; case Token.IF: boolean hasElse = childCount == 3; boolean ambiguousElseClause = context == Context.BEFORE_DANGLING_ELSE && !hasElse; if (ambiguousElseClause) { cc.beginBlock(); } add("if("); add(first); add(")"); if (hasElse) { addNonEmptyExpression( first.getNext(), Context.BEFORE_DANGLING_ELSE, false); add("else"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } else { addNonEmptyExpression(first.getNext(), Context.OTHER, false); Preconditions.checkState(childCount == 2); } if (ambiguousElseClause) { cc.endBlock(); } break; case Token.NULL: case Token.THIS: case Token.FALSE: case Token.TRUE: Preconditions.checkState(childCount == 0); add(Node.tokenToName(type)); break; case Token.CONTINUE: Preconditions.checkState(childCount <= 1); add("continue"); if (childCount == 1) { add(" "); add(first); } cc.endStatement(); break; case Token.DEBUGGER: Preconditions.checkState(childCount == 0); add("debugger"); cc.endStatement(); break; case Token.BREAK: Preconditions.checkState(childCount <= 1); add("break"); if (childCount

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> == 1) { add(" "); add(first); } cc.endStatement(); break; case Token.EXPR_VOID: case Token.EXPR_RESULT: if (type == Token.EXPR_VOID && validation) { throw new Error("Unexpected EXPR_VOID. Should be EXPR_RESULT."); } Preconditions.checkState(childCount == 1); add(first, Context.START_OF_EXPR); cc.endStatement(); break; case Token.NEW: add("new "); int precedence = NodeUtil.precedence(type); // If the first child contains a CALL, then claim higher precedence // to force parens. Otherwise, when parsed, NEW will bind to the // first viable parens if (NodeUtil.containsCall(first)) { precedence = NodeUtil.precedence(first.getType()) + 1; } addExpr(first, precedence); // '()' is optional when no arguments are present Node next = first.getNext(); if (next != null) { add("("); addList(next); add(")"); } break; case Token.STRING: Preconditions.checkState(childCount == 0); add(jsString(n.getString(), outputCharsetEncoder)); break; case Token.DELPROP: Preconditions.checkState(childCount == 1); add("delete "); add(first); break; case Token.OBJECTLIT: { Preconditions.checkState(childCount % 2 == 0); boolean needsParens = (context == Context.START_OF_EXPR); if (needsParens) { add("("); } add("{"); for (Node c = first; c != null; c = c.getNext().getNext()) { if (c != first) { cc.listSeparator(); } // Object literal property names don't have to be quoted if they are // not JavaScript keywords if (c.getType() == Token.STRING && !TokenStream.isKeyword(c.getString()) && TokenStream.isJSIdentifier(c.getString()) && // do not encode literally any non-literal characters that were // unicode escaped. NodeUtil.isLatin(c.getString()))

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> { add(c.getString()); } else { addExpr(c, 1); } add(":"); addExpr(c.getNext(), 1); } add("}"); if (needsParens) { add(")"); } break; } case Token.SWITCH: add("switch("); add(first); add(")"); cc.beginBlock(); addAllSiblings(first.getNext()); cc.endBlock(context == Context.STATEMENT); break; case Token.CASE: Preconditions.checkState(childCount == 2); add("case "); add(first); addCaseBody(last); break; case Token.DEFAULT: Preconditions.checkState(childCount == 1); add("default"); addCaseBody(first); break; case Token.LABEL: Preconditions.checkState(childCount == 2); add(first); add(":"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), true); break; // This node is auto generated in anonymous functions and should just get // ignored for our purposes. case Token.SETNAME: break; default: throw new Error("Unknown type " + type + "\n" + n.toStringTree()); } cc.endSourceMapping(n); } /** * Adds a block or expression, substituting a VOID with an empty statement. * This is used for "for (...);" and "if (...);" type statements. * * @param n The node to print. * @param context The context to determine how the node should be printed. */ private void addNonEmptyExpression( Node n, Context context, boolean allowNonBlockChild) { Node nodeToProcess = n; if (!allowNonBlockChild && n.getType() != Token.BLOCK) { if (validation) { throw new Error("Missing BLOCK child."); } } // Strip unneeded blocks, that is blocks with <2 children unless // the CodePrinter specifically wants to keep them. if (n.getType() == Token.BLOCK ) { int count = getNonEmptyChildCount(n); if (count == 0) { cc.endStatement(true); return;

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> } if (count == 1) { // Hack around a couple of browser bugs: // Safari needs a block around function declarations. // IE6/7 needs a block around DOs. Node firstAndOnlyChild = getFirstNonEmptyChild(n); boolean alwaysWrapInBlock = cc.shouldPreserveExtraBlocks(); if (alwaysWrapInBlock || firstAndOnlyChild.getType() == Token.FUNCTION || firstAndOnlyChild.getType() == Token.DO) { cc.beginBlock(); add(firstAndOnlyChild, Context.STATEMENT); cc.maybeLineBreak(); cc.endBlock(context == Context.STATEMENT); return; } else { // Continue with the only child. nodeToProcess = firstAndOnlyChild; } } } if (nodeToProcess.getType() == Token.EMPTY) { cc.endStatement(true); } else { add(nodeToProcess, context); // VAR doesn't include ';' since it gets used in expressions - so any // VAR in a statement context needs a call to endStatement() here. if (nodeToProcess.getType() == Token.VAR) { cc.endStatement(); } } } /** * Adds a node at the left-hand side of an expression. Unlike * {@link #addExpr(Node,int)}, this preserves information about the context. * * The left side of an expression is special because in the JavaScript * grammar, certain tokens may be parsed differently when they are at * the beginning of a statement. For example, "{}" is parsed as a block, * but "{'x': 'y'}" is parsed as an object literal. */ void addLeftExpr(Node n, int minPrecedence, Context context) { addExpr(n, minPrecedence, context); } void addExpr(Node n, int minPrecedence) { addExpr(n, minPrecedence, Context.OTHER); } private void addExpr(Node n, int minPrecedence, Context context) { if ((NodeUtil.precedence(n.getType()) < minPrecedence) || ((context == Context.IN_FOR_INIT_CLAUSE) && (n.getType() == Token.IN))

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>){ add("("); add(n, clearContextForNoInOperator(context)); add(")"); } else { add(n, context); } } void addList(Node firstInList) { addList(firstInList, true, Context.OTHER); } void addList(Node firstInList, boolean isArrayOrFunctionArgument) { addList(firstInList, isArrayOrFunctionArgument, Context.OTHER); } void addList(Node firstInList, boolean isArrayOrFunctionArgument, Context lhsContext) { for (Node n = firstInList; n != null; n = n.getNext()) { boolean isFirst = n == firstInList; if (isFirst) { addLeftExpr(n, isArrayOrFunctionArgument ? 1 : 0, lhsContext); } else { cc.listSeparator(); addExpr(n, isArrayOrFunctionArgument ? 1 : 0); } } } /** * This function adds a comma-separated list as is specified by an ARRAYLIT * node with the associated skipIndexes array. This is a space optimization * since we avoid creating a whole Node object for each empty array literal * slot. * @param firstInList The first in the node list (chained through the next * property). * @param skipIndexes If not null, then the array of skipped entries in the * array. */ void addList(Node firstInList, int[] skipIndexes) { int nextSlot = 0; int nextSkipSlot = 0; for (Node n = firstInList; n != null; n = n.getNext()) { while (skipIndexes != null && nextSkipSlot < skipIndexes.length) { if (nextSlot == skipIndexes[nextSkipSlot]) { cc.listSeparator(); nextSlot++; nextSkipSlot++; } else { break; } } if (n != firstInList) { cc.listSeparator(); } addExpr(n, 1); nextSlot++; } } void addCaseBody(Node caseBody) { cc.beginCaseBody(); add(caseBody); cc.endCaseBody(); } void addAllSiblings(Node n) {

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> for (Node c = n; c != null; c = c.getNext()) { add(c); } } /** Outputs a js string, using the optimal (single/double) quote character */ static String jsString(String s, CharsetEncoder outputCharsetEncoder) { int singleq = 0, doubleq = 0; // could count the quotes and pick the optimal quote character for (int i = 0; i < s.length(); i++) { switch (s.charAt(i)) { case '"': doubleq++; break; case '\'': singleq++; break; } } String doublequote, singlequote; char quote; if (singleq < doubleq) { // more double quotes so escape the single quotes quote = '\''; doublequote = "\""; singlequote = "\\\'"; } else { // more single quotes so escape the doubles quote = '\"'; doublequote = "\\\""; singlequote = "\'"; } return strEscape(s, quote, doublequote, singlequote, "\\\\", outputCharsetEncoder); } /** Escapes regular expression */ static String regexpEscape(String s, CharsetEncoder outputCharsetEncoder) { return strEscape(s, '/', "\"", "'", "\\", outputCharsetEncoder); } /** * Escapes the given string to a double quoted (") JavaScript/JSON string */ static String escapeToDoubleQuotedJsString(String s) { return strEscape(s, '"', "\\\"", "\'", "\\\\", null); } /* If the user doesn't want to specify an output charset encoder, assume they want Latin/ASCII characters only. */ static String regexpEscape(String s) { return regexpEscape(s, null); } /** Helper to escape javascript string as well as regular expression */ static String strEscape(String s, char quote, String doublequoteEscape, String singlequoteEscape, String backslashEscape, CharsetEncoder outputCharsetEncoder) { StringBuilder sb = new StringBuilder(); sb.append(quote); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); switch (c) { case '\n': sb.append("\\n"); break; case

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>.isLatin(s)) { return s; } // Now going through the string to escape non-latin characters if needed. StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); // Identifiers should always go to Latin1/ ASCII characters because // different browser's rules for valid identifier characters are // crazy. if (c > 0x1F && c < 0x7F) { sb.append(c); } else { appendHexJavaScriptRepresentation(sb, c); } } return sb.toString(); } /** Gets the number of children of this node that are non empty. */ private static int getNonEmptyChildCount(Node n) { int i = 0; for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (c.getType() != Token.EMPTY) { i++; } } return i; } /** Gets the first non-empty child of the given node. */ private static Node getFirstNonEmptyChild(Node n) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (c.getType() != Token.EMPTY) { return c; } } return null; } // Information on the current context. Used for disambiguating special cases. // For example, a "{" could indicate the start of an object literal or a // block, depending on the current context. enum Context { STATEMENT, BEFORE_DANGLING_ELSE, // a hack to resolve the else-clause ambiguity START_OF_EXPR, PRESERVE_BLOCK, // Are we inside the init clause of a for loop? If so, the containing // expression can't contain an in operator. Pass this context flag down // until we reach expressions which no longer have the limitation. IN_FOR_INIT_CLAUSE, OTHER } private Context getContextForNonEmptyExpression(Context currentContext) { return currentContext == Context.BEFORE_DANGLING_ELSE ? Context.BEFORE_DANGLING_ELSE : Context.OTHER;

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>ertype of a record type * of the form { b : TYPE_2, a : TYPE_1 } because B can be assigned to * A and matches all constraints. Similarly, a defined type can be assigned * to a record type so long as that defined type matches all property * constraints of the record type. A record type of the form { a : A, b : B } * can be assigned to a record of type { a : A }. * * */ public class RecordType extends PrototypeObjectType { private static final long serialVersionUID = 1L; private Map<String, JSType> properties = new HashMap<String, JSType>(); private boolean isFrozen = false; /** * Creates a record type. * * @param registry The type registry under which this type lives. * @param properties A map of all the properties of this record type. */ RecordType(JSTypeRegistry registry, Map<String, JSType> properties) { super(registry, null, null); for (String property : properties.keySet()) { defineDeclaredProperty(property, properties.get(property), false); } // Freeze the record type. isFrozen = true; } @Override public boolean equals(Object other) { if (!(other instanceof RecordType)) { return false; } // Compare properties. RecordType otherRecord = (RecordType) other; return otherRecord.properties.equals(properties); } @Override public ObjectType getImplicitPrototype() { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { if (isFrozen) { return false; } if (!inferred) { properties.put(propertyName, type); } return super.defineProperty(propertyName, type, inferred, inExterns); } @Override public JSType getLeastSupertype(JSType that) { if (!that.isRecordType()) { return super.getLeastSupertype(that); } RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The least supertype consist of those properties of the record

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> // type that both record types hold in common both by name and // type of the properties themselves. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && thatRecord.getPropertyType(property).equals( getPropertyType(property))) { builder.addProperty(property, getPropertyType(property)); } } return builder.build(); } @Override public JSType getGreatestSubtype(JSType that) { if (that.isRecordType()) { RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The greatest subtype consists of those *unique* properties of both // record types. If any property conflicts, then the NO_TYPE type // is returned. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && !thatRecord.getPropertyType(property).equals( getPropertyType(property))) { return registry.getNativeObjectType(JSTypeNative.NO_TYPE); } builder.addProperty(property, getPropertyType(property)); } for (String property : thatRecord.properties.keySet()) { if (!hasProperty(property)) { builder.addProperty(property, thatRecord.getPropertyType(property)); } } return builder.build(); } JSType greatestSubtype = super.getGreatestSubtype(that); if (greatestSubtype.isNoObjectType() && !that.isNoObjectType()) { // In this branch, the other type is some object type. We find // the greatest subtype with the following algorithm: // 1) For each property "x" of this record type, take the union // of all classes with a property "x" with a compatible property type. // and which are a subtype of {@code that}. // 2) Take the intersection of all of these unions. for (Map.Entry<String, JSType> entry : properties.entrySet()) { String propName = entry.getKey(); JSType propType = entry.getValue(); UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (ObjectType alt : registry.getTypesWithProperty(propName)) { JSType altPropType = alt.getPropertyType(propName); if (

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>altPropType != null && !alt.equals(this) && alt.isSubtype(that) && (propType.isUnknownType() || altPropType.isUnknownType() || altPropType.equals(propType))) { builder.addAlternate(alt); } } greatestSubtype = greatestSubtype.getLeastSupertype(builder.build()); } } return greatestSubtype; } @Override public boolean isRecordType() { return true; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } // Top of the record types is the empty record, or OBJECT_TYPE. if (registry.getNativeObjectType( JSTypeNative.OBJECT_TYPE).isSubtype(that)) { return true; } // A type is a subtype of a record type if it itself is a record // type and it has at least the same members as the parent record type // with the same types. if (!that.isRecordType()) { return false; } return RecordType.isSubtype(this, (RecordType) that); } /** Determines if typeA is a subtype of typeB */ static boolean isSubtype(ObjectType typeA, RecordType typeB) { // typeA is a subtype of record type typeB iff: // 1) typeA has all the properties declared in typeB. // 2) And for each property of typeB, // 2a) if the property of typeA is declared, it must be equal // to the type of the property of typeB, // 2b) otherwise, it must be a subtype of the property of typeB. // // To figure out why this is true, consider the following pseudo-code: // /** @type {{a: (Object,null)}} */ var x; // /** @type {{a: !Object}} */ var y; // var z = {a: {}}; // x.a = null; // // y cannot be assigned to x, because line 4 would violate y's declared // properties. But z can be assigned to x. Even though z and y are the // same type, the properties of z are inferred--

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>and so an assignment // to the property of z would not violate any restrictions on it. for (String property : typeB.properties.keySet()) { if (!typeA.hasProperty(property)) { return false; } JSType propA = typeA.getPropertyType(property); JSType propB = typeB.getPropertyType(property); if (!propA.isUnknownType() && !propB.isUnknownType()) { if (typeA.isPropertyTypeDeclared(property)) { if (!propA.equals(propB)) { return false; } } else { if (!propA.isSubtype(propB)) { return false; } } } } return true; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{ "); int i = 0; for (String property : properties.keySet()) { if (i > 0) { sb.append(", "); } sb.append(property); sb.append(" : "); sb.append(properties.get(property).toString()); ++i; } sb.append(" }"); return sb.toString(); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { for (Map.Entry<String, JSType> entry : properties.entrySet()) { JSType type = entry.getValue(); JSType resolvedType = type.resolve(t, scope); if (type != resolvedType) { properties.put(entry.getKey(), resolvedType); } } return super.resolveInternal(t, scope); } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> public String getInputName() { if (input == null) return "<non-file>"; else return input.getName(); } public boolean isNoShadow() { if (info != null && info.isNoShadow()) { return true; } else { return false; } } @Override public boolean equals(Object other) { if (!(other instanceof Var)) { return false; } Var otherVar = (Var) other; return otherVar.nameNode == nameNode; } @Override public int hashCode() { return nameNode.hashCode(); } @Override public String toString() { return "Scope.Var " + name; } } /** * Creates a Scope given the parent Scope and the root node of the scope. * @param parent The parent Scope. Cannot be null. * @param rootNode Typically the FUNCTION node. */ Scope(Scope parent, Node rootNode) { Preconditions.checkNotNull(parent); Preconditions.checkArgument(rootNode != parent.rootNode); this.parent = parent; this.rootNode = rootNode; JSType nodeType = rootNode.getJSType(); if (nodeType != null && nodeType instanceof FunctionType) { thisType = ((FunctionType) nodeType).getTypeOfThis(); } else { thisType = parent.thisType; } this.isBottom = false; } /** * Creates a global Scope. * @param rootNode Typically the global BLOCK node. */ Scope(Node rootNode, AbstractCompiler compiler) { this.parent = null; this.rootNode = rootNode; thisType = compiler.getTypeRegistry().getNativeObjectType(GLOBAL_THIS); this.isBottom = false; } /** * Creates a empty Scope (bottom of the lattice). * @param rootNode Typically a FUNCTION node or the global BLOCK node. * @param thisType the type of {@code this} in this scope */ Scope(Node rootNode, ObjectType thisType) { this.parent = null; this.rootNode = rootNode; this.thisType = thisType; this.isBottom = true; } /** Whether this is the bottom of the lattice. */ boolean isBottom

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>/* * Copyright 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; /** * This interface defines how objects capable of creating scopes from the parse * tree behave. * * */ interface ScopeCreator { /** * Creates a {@link Scope} object. * * @param n the root node (either a FUNCTION node, a SCRIPT node, or a * synthetic block node whose children are all SCRIPT nodes) * @param parent the parent Scope object (may be null) */ Scope createScope(Node n, Scope parent); }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> String name = callName.getString(); int dollarIndex = name.lastIndexOf('$'); if (dollarIndex != -1) { methodName = name.substring(dollarIndex + 1); } } if (methodName != null) { if (methodName.equals("inherits")) { return SubclassType.INHERITS; } else if (methodName.equals("mixin")) { return SubclassType.MIXIN; } } return null; } @Override public boolean isSuperClassReference(String propertyName) { return "superClass_".equals(propertyName); } /** * Given a qualified name node, strip "prototype" off the end. * * Examples of this transformation: * a.b.c => a.b.c * a.b.c.prototype => a.b.c */ private Node stripPrototype(Node qualifiedName) { if (qualifiedName.getType() == Token.GETPROP && qualifiedName.getLastChild().getString().equals("prototype")) { return qualifiedName.getFirstChild(); } return qualifiedName; } /** * Exctracts X from goog.provide('X'), if the applied Node is goog. * * @return The extracted class name, or null. */ @Override public String extractClassNameIfProvide(Node node, Node parent){ return extractClassNameIfGoog(node, parent, "goog.provide"); } /** * Exctracts X from goog.require('X'), if the applied Node is goog. * * @return The extracted class name, or null. */ @Override public String extractClassNameIfRequire(Node node, Node parent){ return extractClassNameIfGoog(node, parent, "goog.require"); } private static String extractClassNameIfGoog(Node node, Node parent, String functionName){ String className = null; if (NodeUtil.isExprCall(parent)) { Node callee = node.getFirstChild(); if (callee != null && callee.getType() == Token.GETPROP) { String qualifiedName = callee.getQualifiedName(); if ((functionName).equals(qualifiedName)) { className = callee.getNext().getString(); } } } return className; }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> /** * Use closure's implementation. * @return closure's function name for exporting properties. */ @Override public String getExportPropertyFunction() { return "goog.exportProperty"; } /** * Use closure's implementation. * @return closure's function name for exporting symbols. */ @Override public String getExportSymbolFunction() { return "goog.exportSymbol"; } @Override public List<String> identifyTypeDeclarationCall(Node n) { Node callName = n.getFirstChild(); if ("goog.addDependency".equals(callName.getQualifiedName()) && n.getChildCount() >= 3) { Node typeArray = callName.getNext().getNext(); if (typeArray.getType() == Token.ARRAYLIT) { List<String> typeNames = Lists.newArrayList(); for (Node name = typeArray.getFirstChild(); name != null; name = name.getNext()) { if (name.getType() == Token.STRING) { typeNames.add(name.getString()); } } return typeNames; } } return null; } @Override public String identifyTypeDefAssign(Node n) { Node firstChild = n.getFirstChild(); int type = n.getType(); if (type == Token.ASSIGN) { if (TYPEDEF_NAME.equals(n.getLastChild().getQualifiedName())) { return firstChild.getQualifiedName(); } } else if (type == Token.VAR && firstChild.hasChildren()) { if (TYPEDEF_NAME.equals( firstChild.getFirstChild().getQualifiedName())) { return firstChild.getString(); } } return null; } @Override public String getAbstractMethodName() { return "goog.abstractMethod"; } @Override public String getSingletonGetterClassName(Node callNode) { Node callName = callNode.getFirstChild(); if (!"goog.addSingletonGetter".equals(callName.getQualifiedName()) || callName.getChildCount() != 2) { return null; } Node classNode = callName.getNext(); if (!classNode.isQualifiedName()) { return null; } return callName.getNext().getQualifiedName(); } @Override public void applySingletonGetter(

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>FunctionType functionType, FunctionType getterType, ObjectType objectType) { functionType.defineDeclaredProperty("getInstance", getterType, false); functionType.defineDeclaredProperty("instance_", objectType, false); } @Override public String getGlobalObject() { return "goog.global"; } private final Set<String> propertyTestFunctions = ImmutableSet.of( "goog.isDef", "goog.isNull", "goog.isDefAndNotNull", "goog.isString", "goog.isNumber", "goog.isBoolean", "goog.isFunction", "goog.isArray", "goog.isObject"); @Override public boolean isPropertyTestFunction(Node call) { Preconditions.checkArgument(call.getType() == Token.CALL); return propertyTestFunctions.contains( call.getFirstChild().getQualifiedName()); } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) { Preconditions.checkArgument(callNode.getType() == Token.CALL); Node callName = callNode.getFirstChild(); if (!"goog.reflect.object".equals(callName.getQualifiedName()) || callName.getChildCount() != 2) { return null; } Node typeNode = callName.getNext(); if (!typeNode.isQualifiedName()) { return null; } Node objectNode = typeNode.getNext(); if (objectNode.getType() != Token.OBJECTLIT) { t.getCompiler().report(JSError.make(t.getSourceName(), callNode, OBJECTLIT_EXPECTED)); return null; } return new ObjectLiteralCast(typeNode.getQualifiedName(), typeNode.getNext()); } /** * {@inheritDoc} */ @Override public boolean isOptionalParameter(Node parameter) { return false; } /** * {@inheritDoc} */ @Override public boolean isVarArgsParameter(Node parameter) { return false; } /** * {@inheritDoc} */ @Override public boolean isPrivate(String name) { return false; } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> default: Kit.codeBug(); } return null; } private static class NumberNode extends Node { private static final long serialVersionUID = 1L; NumberNode(double number) { super(Token.NUMBER); this.number = number; } public NumberNode(double number, int lineno, int charno) { super(Token.NUMBER, lineno, charno); this.number = number; } @Override public double getDouble() { return this.number; } @Override public void setDouble(double d) { this.number = d; } @Override public boolean isEquivalentTo(Node node) { return (node instanceof NumberNode && getDouble() == ((NumberNode) node).getDouble()); } private double number; } private static class StringNode extends Node { private static final long serialVersionUID = 1L; StringNode(int type, String str) { super(type); if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } StringNode(int type, String str, int lineno, int charno) { super(type, lineno, charno); if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } /** returns the string content. * @return non null. */ @Override public String getString() { return this.str; } /** sets the string content. * @param str the new value. Non null. */ @Override public void setString(String str) { if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } @Override public boolean isEquivalentTo(Node node) { return (node instanceof StringNode && this.str.equals(((StringNode) node).str)); } /** * If the property is not defined, this was not a quoted key. The * QUOTED_PROP int property is only assigned to STRING tokens used as * object lit keys. * @return true if this was a quoted string key in an object literal. */ @Override public boolean isQuotedString

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>() { return last; } public Node getNext() { return next; } public Node getChildBefore(Node child) { if (child == first) return null; Node n = first; while (n.next != child) { n = n.next; if (n == null) throw new RuntimeException("node is not a child"); } return n; } public Node getChildAtIndex(int i) { Node n = first; while (i > 0) { n = n.next; i--; } return n; } public Node getLastSibling() { Node n = this; while (n.next != null) { n = n.next; } return n; } public void addChildToFront(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = first; first = child; if (last == null) { last = child; } } public void addChildToBack(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = null; if (last == null) { first = last = child; return; } last.next = child; last = child; } public void addChildrenToFront(Node children) { for (Node child = children; child != null; child = child.next) { Preconditions.checkArgument(child.parent == null); child.parent = this; } Node lastSib = children.getLastSibling(); lastSib.next = first; first = children; if (last == null) { last = lastSib; } } public void addChildrenToBack(Node children) { for (Node child = children; child != null; child = child.next) { // Hmmm... IRFactory doesn't remove before calling this. Preconditions.checkArgument(child.parent == null); child.parent = this; } if (last != null) { last.next = children; }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Double(double s) throws UnsupportedOperationException { if (this.getType() == Token.NUMBER) { throw new IllegalStateException( "Number node not created with Node.newNumber"); } else { throw new UnsupportedOperationException( this + " is not a string node"); } } /** Can only be called when node has String context. */ public String getString() throws UnsupportedOperationException { if (this.getType() == Token.STRING) { throw new IllegalStateException( "String node not created with Node.newString"); } else { throw new UnsupportedOperationException( this + " is not a string node"); } } /** Can only be called when node has String context. */ public void setString(String s) throws UnsupportedOperationException { if (this.getType() == Token.STRING) { throw new IllegalStateException( "String node not created with Node.newString"); } else { throw new UnsupportedOperationException( this + " is not a string node"); } } @Override public String toString() { return toString(true, true, true); } public String toString( boolean printSource, boolean printAnnotations, boolean printType) { if (Token.printTrees) { StringBuilder sb = new StringBuilder(); toString(sb, printSource, printAnnotations, printType); return sb.toString(); } return String.valueOf(type); } private void toString( StringBuilder sb, boolean printSource, boolean printAnnotations, boolean printType) { if (Token.printTrees) { sb.append(Token.name(type)); if (this instanceof StringNode) { sb.append(' '); sb.append(getString()); } else if (type == Token.FUNCTION) { sb.append(' '); sb.append(first.getString()); } else if (this instanceof ScriptOrFnNode) { ScriptOrFnNode sof = (ScriptOrFnNode)this; if (this instanceof FunctionNode) { FunctionNode fn = (FunctionNode)this; sb.append(' '); sb.append(fn.getFunctionName()); } if (printSource) { sb.append(" [source name: "); sb.append(sof.getSourceName()); sb.append("] [encoded source length: "); sb.append

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> jsType.toString(); if (jsTypeString != null) { sb.append(" : "); sb.append(jsTypeString); } } } } } public String toStringTree() { return toStringTreeImpl(); } private String toStringTreeImpl() { try { StringBuffer s = new StringBuffer(); appendStringTree(s); return s.toString(); } catch (IOException e) { throw new RuntimeException("Should not happen\n" + e); } } public void appendStringTree(Appendable appendable) throws IOException { toStringTreeHelper(this, 0, appendable); } private static void toStringTreeHelper(Node n, int level, Appendable sb) throws IOException { if (Token.printTrees) { for (int i = 0; i != level; ++i) { sb.append(" "); } sb.append(n.toString()); sb.append('\n'); for (Node cursor = n.getFirstChild(); cursor != null; cursor = cursor.getNext()) { toStringTreeHelper(cursor, level + 1, sb); } } } int type; // type of the node; Token.NAME for example Node next; // next sibling private Node first; // first element of a linked list of children private Node last; // last element of a linked list of children /** * Linked list of properties. Since vast majority of nodes would have * no more then 2 properties, linked list saves memory and provides * fast lookup. If this does not holds, propListHead can be replaced * by UintMap. */ private PropListItem propListHead; /** * COLUMN_BITS represents how many of the lower-order bits of * sourcePosition are reserved for storing the column number. * Bits above these store the line number. * This gives us decent position information for everything except * files already passed through a minimizer, where lines might * be longer than 4096 characters. */ public static final int COLUMN_BITS = 12; /** * MAX_COLUMN_NUMBER represents the maximum column number that can * be represented. JSCompiler's modifications to Rhino cause all * tokens located beyond the maximum column to

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> Node.children is in for // loops, this branch is extremely unlikely. return (new SiblingNodeIterable(start)).iterator(); } } public boolean hasNext() { return current != null; } public Node next() { if (current == null) { throw new NoSuchElementException(); } try { return current; } finally { current = current.getNext(); } } public void remove() { throw new UnsupportedOperationException(); } } //========================================================================== // Accessors public Node getParent() { return parent; } /** * Gets the ancestor node relative to this. * @param level 0 = this, 1 = the parent, etc. */ public Node getAncestor(int level) { Preconditions.checkArgument(level >= 0); Node node = this; while(node != null && level-- > 0) { node = node.getParent(); } return node; } /** * Iterates all of the node's ancestors excluding itself. */ public AncestorIterable getAncestors() { return new AncestorIterable(this.getParent()); } /** * Iterator to go up the ancestor tree. */ public static class AncestorIterable implements Iterable<Node> { private Node cur; /** * @param cur The node to start. */ AncestorIterable(Node cur) { this.cur = cur; } public Iterator<Node> iterator() { return new Iterator<Node>() { public boolean hasNext() { return cur != null; } public Node next() { if (!hasNext()) throw new NoSuchElementException(); Node n = cur; cur = cur.getParent(); return n; } public void remove() { throw new UnsupportedOperationException(); } }; } } /** * Check for one child more efficiently than by iterating over all the * children as is done with Node.getChildCount(). * @return Whether the node has exactly one child. */ public boolean hasOneChild() { return first != null && first == last; } /** * Check for more than one child more efficiently than by iterating over all * the children as is done with Node.getChildCount(). * @return Whether the node more than

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> one child. */ public boolean hasMoreThanOneChild() { return first != null && first != last; } public int getChildCount() { int c = 0; for (Node n = first; n != null; n = n.next) c++; return c; } // Intended for testing and verification only. public boolean hasChild(Node child) { for (Node n = first; n != null; n = n.getNext()) { if (child == n) { return true; } } return false; } /** * Checks if the subtree under this node is the same as another subtree. * Returns null if it's equal, or a message describing the differences. */ public String checkTreeEquals(Node node2) { NodeMismatch diff = checkTreeEqualsImpl(node2); if (diff != null) { return "Node tree inequality:" + "\nTree1:\n" + toStringTree() + "\n\nTree2:\n" + node2.toStringTree(); } return null; } /** * If this is a compilation pass and not a test, do not construct error * strings. Instead return true if the trees are equal. */ public boolean checkTreeEqualsSilent(Node node2) { return checkTreeEqualsImpl(node2) == null; } /** * Compare this node to node2 recursively and return the first pair * of nodes that differs doing a preorder depth-first traversal. * Package private for testing. Returns null if the nodes are equivalent. */ NodeMismatch checkTreeEqualsImpl(Node node2) { boolean eq = false; if (type == node2.getType() && getChildCount() == node2.getChildCount() && getClass() == node2.getClass()) { eq = this.isEquivalentTo(node2); } if (!eq) { return new NodeMismatch(this, node2); } NodeMismatch res = null; Node n, n2; for (n = first, n2 = node2.first; res == null && n != null; n = n.next, n2 = n2.next) { res = n.checkTreeEqualsImpl(n2

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>); if (res != null) { return res; } } return res; } /** * Checks if the subtree under this node is the same as another subtree * including types. Returns null if it's equal, or a message describing the * differences. */ public boolean checkTreeTypeAwareEqualsSilent(Node node2) { return checkTreeTypeAwareEqualsImpl(node2) == null; } /** * Compare this node to node2 recursively and return the first pair * of nodes that differs doing a preorder depth-first traversal. * Package private for testing. Returns null if the nodes are equivalent. */ NodeMismatch checkTreeTypeAwareEqualsImpl(Node node2) { boolean eq = false; if (type == node2.getType() && getChildCount() == node2.getChildCount() && getClass() == node2.getClass() && Objects.equal(jsType, node2.getJSType())) { eq = this.isEquivalentTo(node2); } if (!eq) { return new NodeMismatch(this, node2); } NodeMismatch res = null; Node n, n2; for (n = first, n2 = node2.first; res == null && n != null; n = n.next, n2 = n2.next) { res = n.checkTreeTypeAwareEqualsImpl(n2); if (res != null) { return res; } } return res; } public static String tokenToName(int token) { switch (token) { case Token.ERROR: return "error"; case Token.EOF: return "eof"; case Token.EOL: return "eol"; case Token.ENTERWITH: return "enterwith"; case Token.LEAVEWITH: return "leavewith"; case Token.RETURN: return "return"; case Token.GOTO: return "goto"; case Token.IFEQ: return "ifeq"; case Token.IFNE: return "ifne"; case Token.SETNAME: return "setname"; case Token.BITOR: return "bitor"; case Token.BITXOR: return "bitxor"; case Token.BIT

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>.name(getType())); putBooleanProp(NO_SIDE_EFFECTS_CALL, true); } /** * Returns true if this node is a function or constructor call that * has no side effects. */ public boolean isNoSideEffectsCall() { return getBooleanProp(NO_SIDE_EFFECTS_CALL); } /** * This should only be called for STRING nodes created in object lits. */ public boolean isQuotedString() { return false; } /** * This should only be called for STRING nodes created in object lits. */ public void setQuotedString() { Kit.codeBug(); } static class NodeMismatch { final Node nodeA; final Node nodeB; NodeMismatch(Node nodeA, Node nodeB) { this.nodeA = nodeA; this.nodeB = nodeB; } @Override public boolean equals(Object object) { if (object instanceof NodeMismatch) { NodeMismatch that = (NodeMismatch) object; return that.nodeA.equals(this.nodeA) && that.nodeB.equals(this.nodeB); } return false; } @Override public int hashCode() { return Objects.hashCode(nodeA, nodeB); } } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Override public boolean isNullable() { return false; } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isNumberValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return "number"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNumberType(); } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE); } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; /** * Traversal callback that finds method invocations of the form * * <pre> * call * getprop * ... * string * ... * </pre> * * and invokes a method defined by subclasses for processing these invocations. * * */ abstract class InvocationsCallback extends AbstractPostOrderCallback { public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() != Token.CALL) { return; } Node function = n.getFirstChild(); if (function.getType() != Token.GETPROP) { return; } Node nameNode = function.getFirstChild().getNext(); // Don't care about numerical or variable indexes if (nameNode.getType() != Token.STRING) { return; } visit(t, n, parent, nameNode.getString()); } /** * Called for each callnode that is a method invocation. * * @param callNode node of type call * @param parent parent of callNode * @param callName name of method invoked by first child of call */ abstract void visit(NodeTraversal t, Node callNode, Node parent, String callName); }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> constructor; InstanceObjectType(JSTypeRegistry registry, FunctionType constructor) { this(registry, constructor, false); } InstanceObjectType(JSTypeRegistry registry, FunctionType constructor, boolean isNativeType) { super(registry, null, null, isNativeType); Preconditions.checkNotNull(constructor); this.constructor = constructor; } @Override public String getReferenceName() { return getConstructor().getReferenceName(); } @Override public boolean hasReferenceName() { return getConstructor().hasReferenceName(); } @Override public ObjectType getImplicitPrototype() { return getConstructor().getPrototype(); } @Override public FunctionType getConstructor() { return constructor; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { ObjectType proto = getImplicitPrototype(); if (proto != null && proto.hasOwnDeclaredProperty(name)) { return false; } return super.defineProperty(name, type, inferred, inExterns); } @Override public String toString() { return constructor.getReferenceName(); } @Override boolean isTheObjectType() { return getConstructor().isNative() && "Object".equals(getReferenceName()); } @Override public boolean isInstanceType() { return true; } @Override public boolean isArrayType() { return getConstructor().isNative() && "Array".equals(getReferenceName()); } @Override public boolean isStringObjectType() { return getConstructor().isNative() && "String".equals(getReferenceName()); } @Override public boolean isBooleanObjectType() { return getConstructor().isNative() && "Boolean".equals(getReferenceName()); } @Override public boolean isNumberObjectType() { return getConstructor().isNative() && "Number".equals(getReferenceName()); } @Override public boolean isDateType() { return getConstructor().isNative() && "Date".equals(getReferenceName()); } @Override public boolean isRegexpType() { return getConstructor().isNative() && "RegExp".equals(getReferenceName()); } @Override public boolean isNominalType() { return hasReferenceName(); } @Override public boolean equals(Object that) { if

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> (this == that) { return true; } else if (that instanceof JSType && this.isNominalType()) { ObjectType thatObj = ObjectType.cast((JSType) that); if (thatObj != null && thatObj.isNominalType()) { return getReferenceName().equals(thatObj.getReferenceName()); } } return false; } /** * If this is equal to a NamedType object, its hashCode must be equal * to the hashCode of the NamedType object. */ @Override public int hashCode() { if (hasReferenceName()) { return getReferenceName().hashCode(); } else { return super.hashCode(); } } @Override public Iterable<ObjectType> getCtorImplementedInterfaces() { return getConstructor().getImplementedInterfaces(); } // The owner will always be a resolved type, so there's no need to set // the constructor in resolveInternal. // (it would lead to infinite loops if we did). // JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>1L; NullType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNullType() { return true; } @Override public boolean isNullable() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isNullType() || that.isVoidType()) { return TRUE; } if (that.isUnknownType() || that.isNullable()) { return UNKNOWN; } return FALSE; } @Override public String toString() { return "null"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNullType(); } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>ToImplementors.put(interfaceInstance.getReferenceName(), type); } /** * Returns a collection of types that directly implement {@code * interfaceInstance}. Subtypes of implementing types are not guaranteed to * be returned. {@code interfaceInstance} must be an ObjectType for the * instance of the interface. */ public Collection<FunctionType> getDirectImplementors( ObjectType interfaceInstance) { return interfaceToImplementors.get(interfaceInstance.getReferenceName()); } /** * Records declared type names. Given the limited scopes of JavaScript, all * named types are dumped in a common global scope. We may need to revise this * assumption in the future. * * @param name The name of the type to be recorded. * @param t The actual type being associated with the name. * @return True if this name is not already defined, false otherwise. */ public boolean declareType(String name, JSType t) { if (namesToTypes.containsKey(name)) { return false; } register(t, name); return true; } /** * Records a forward-declared type name. We will not emit errors if this * type name never resolves to anything. */ public void forwardDeclareType(String name) { forwardDeclaredTypes.add(name); } /** * Whether this is a forward-declared type name. */ public boolean isForwardDeclaredType(String name) { return forwardDeclaredTypes.contains(name); } /** Determines whether the given JS package exists. */ public boolean hasNamespace(String name) { return namespaces.contains(name); } /** * Looks up a type by name. * * @param jsTypeName The name string. * @return the corresponding JSType object or {@code null} it cannot be found */ public JSType getType(String jsTypeName) { // TODO(user): Push every local type name out of namesToTypes so that // NamedType#resolve is correct. if (jsTypeName.equals(templateTypeName)) { return templateType; } return namesToTypes.get(jsTypeName); } public JSType getNativeType(JSTypeNative typeId) { return nativeTypes[typeId.ordinal()]; } public ObjectType getNative

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Type existingFunctionType, JSType returnType) { return new FunctionType( this, existingFunctionType.getReferenceName(), /** source node */ null, existingFunctionType.getParametersNode(), returnType, existingFunctionType.getTypeOfThis(), existingFunctionType.getTemplateTypeName()); } /** * Creates a function type which can act as a constructor. * @param returnType the function's return type * @param lastVarArgs whether the last parameter type should be considered as * an extensible var_args parameter * @param parameterTypes the parameters' types */ public FunctionType createConstructorType(JSType returnType, boolean lastVarArgs, JSType... parameterTypes) { if (lastVarArgs) { return createConstructorTypeWithVarArgs(returnType, parameterTypes); } else { return createConstructorType(returnType, parameterTypes); } } /** * Create an object type. */ public ObjectType createObjectType(ObjectType implicitPrototype) { return createObjectType(null, null, implicitPrototype); } /** * Creates a record type. */ public RecordType createRecordType(Map<String, JSType> properties) { return new RecordType(this, properties); } /** * Create an object type. */ public ObjectType createObjectType(String name, Node n, ObjectType implicitPrototype) { return new PrototypeObjectType(this, name, implicitPrototype); } /** * Create an anonymous object type. */ public ObjectType createAnonymousObjectType() { return createObjectType(null, null, null); } /** * Creates a constructor function type. * @param name the function's name or {@code null} to indicate that the * function is anonymous. * @param source the node defining this function. Its type * ({@link Node#getType()}) must be {@link Token#FUNCTION}. * @param parameters the function's parameters or {@code null} * to indicate that the parameter types are unknown. * @param returnType the function's return type or {@code null} to indicate * that the return type is unknown. */ public FunctionType createConstructorType(String name, Node source, Node parameters, JSType returnType) { return new FunctionType(this, name, source, parameters, returnType, null, null,

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> true, false); } /** * Creates an interface function type. * @param name the function's name * @param source the node defining this function. Its type * ({@link Node#getType()}) must be {@link Token#FUNCTION}. */ public FunctionType createInterfaceType(String name, Node source) { return new FunctionType(this, name, source); } /** * Creates a parameterized type. */ public ParameterizedType createParameterizedType( ObjectType objectType, JSType parameterType) { return new ParameterizedType(this, objectType, parameterType); } /** * Identifies the name of an enum before we actually declare it. */ public void identifyEnumName(String name) { enumTypeNames.add(name); } /** * Creates a RecordType from the nodes representing said record type. * @param n The node with type info. * @param sourceName The source file name. * @param scope A scope for doing type name lookups. */ public JSType createRecordTypeFromNodes(Node n, String sourceName, StaticScope<JSType> scope) { RecordTypeBuilder builder = new RecordTypeBuilder(this); // For each of the fields in the record type. for (Node fieldTypeNode = n.getFirstChild(); fieldTypeNode != null; fieldTypeNode = fieldTypeNode.getNext()) { // Get the property's name. Node fieldNameNode = fieldTypeNode; boolean hasType = false; if (fieldTypeNode.getType() == Token.COLON) { fieldNameNode = fieldTypeNode.getFirstChild(); hasType = true; } String fieldName = fieldNameNode.getString(); // TODO(user): Move this into the lexer/parser. // Remove the string literal characters around a field name, // if any. if (fieldName.startsWith("'") || fieldName.startsWith("\"")) { fieldName = fieldName.substring(1, fieldName.length() - 1); } // Get the property's type. JSType fieldType = null; if (hasType) { // We have a declared type. fieldType = createFromTypeNodes( fieldTypeNode.getLastChild(), sourceName, scope); } else { // Otherwise, the type is UNKNOWN. fieldType =

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> getNativeType(JSTypeNative.UNKNOWN_TYPE); } // Add the property to the record. builder.addProperty(fieldName, fieldType); } return builder.build(); } /** * Creates a JSType from the nodes representing a type. * @param n The node with type info. * @param sourceName The source file name. * @param scope A scope for doing type name lookups. */ public JSType createFromTypeNodes(Node n, String sourceName, StaticScope<JSType> scope) { switch (n.getType()) { case Token.LC: // Record type. return createRecordTypeFromNodes(n.getFirstChild(), sourceName, scope); case Token.BANG: // Not nullable return createFromTypeNodes(n.getFirstChild(), sourceName, scope) .restrictByNotNullOrUndefined(); case Token.QMARK: // Nullable return createNullableType( createFromTypeNodes(n.getFirstChild(), sourceName, scope)); case Token.EQUALS: // Optional return createOptionalType( createFromTypeNodes(n.getFirstChild(), sourceName, scope)); case Token.ELLIPSIS: // Var args return createOptionalType( createFromTypeNodes(n.getFirstChild(), sourceName, scope)); case Token.STAR: // The AllType return getNativeType(ALL_TYPE); case Token.LB: // Array type // TODO(nicksantos): Enforce membership restrictions on the Array. return getNativeType(ARRAY_TYPE); case Token.PIPE: // Union type UnionTypeBuilder builder = new UnionTypeBuilder(this); for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { builder.addAlternate(createFromTypeNodes(child, sourceName, scope)); } return builder.build(); case Token.EMPTY: // When the return value of a function is not specified return getNativeType(UNKNOWN_TYPE); case Token.VOID: // Only allowed in the return value of a function. return getNativeType(VOID_TYPE); case Token.STRING: JSType namedType = getType(scope, n.getString(), sourceName, n.getLineno(), n.getCharno()); if ((namedType

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> instanceof ObjectType) && !(enumTypeNames.contains(n.getString()))) { Node typeList = n.getFirstChild(); if (typeList != null && ("Array".equals(n.getString()) || "Object".equals(n.getString()))) { JSType parameterType = createFromTypeNodes( typeList.getLastChild(), sourceName, scope); namedType = new ParameterizedType( this, (ObjectType) namedType, parameterType); if (typeList.hasMoreThanOneChild()) { JSType indexType = createFromTypeNodes( typeList.getFirstChild(), sourceName, scope); namedType = new IndexedType( this, (ObjectType) namedType, indexType); } } return createNullableType(namedType); } else { return namedType; } case Token.FUNCTION: ObjectType thisType = null; Node current = n.getFirstChild(); if (current.getType() == Token.THIS) { Node thisNode = current.getFirstChild(); thisType = ObjectType.cast( createFromTypeNodes(thisNode, sourceName, scope) .restrictByNotNullOrUndefined()); if (thisType == null) { reporter.warning( ScriptRuntime.getMessage0("msg.jsdoc.function.thisnotobject"), sourceName, thisNode.getLineno(), "", thisNode.getCharno()); } current = current.getNext(); } FunctionParamBuilder paramBuilder = new FunctionParamBuilder(this); if (current.getType() == Token.LP) { Node args = current.getFirstChild(); for (Node arg = current.getFirstChild(); arg != null; arg = arg.getNext()) { if (arg.getType() == Token.ELLIPSIS) { if (arg.getChildCount() == 0) { paramBuilder.addVarArgs(getNativeType(UNKNOWN_TYPE)); } else { paramBuilder.addVarArgs( createFromTypeNodes( arg.getFirstChild(), sourceName, scope)); } } else { JSType type = createFromTypeNodes(arg, sourceName, scope); if (arg.getType() == Token.EQUALS) { boolean addSuccess = paramBuilder.addOptionalParams(type); if (!addSuccess

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>) { reporter.warning( ScriptRuntime.getMessage0("msg.jsdoc.function.varargs"), sourceName, arg.getLineno(), "", arg.getCharno()); } } else { paramBuilder.addRequiredParams(type); } } } current = current.getNext(); } JSType returnType = createFromTypeNodes(current, sourceName, scope); return new FunctionType(this, null, null, paramBuilder.build(), returnType, thisType, null); } throw new IllegalStateException( "Unexpected node in type expression: " + n.toString()); } /** * Sets the template type name. */ public void setTemplateTypeName(String name) { templateTypeName = name; templateType = new TemplateType(this, name); } /** * Clears the template type name. */ public void clearTemplateTypeName() { templateTypeName = null; templateType = null; } }

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>; } public boolean isCheckedUnknownType() { return false; } public boolean isUnionType() { return false; } public boolean isFunctionType() { return false; } public boolean isEnumElementType() { return false; } public boolean isEnumType() { return false; } public boolean isNamedType() { return false; } public boolean isRecordType() { return false; } public boolean isTemplateType() { return false; } /** * Tests whether this type is an {@code Object}, or any subtype thereof. * @return {@code this &lt;: Object} */ public boolean isObject() { return false; } /** * Whether this type is a {@link FunctionType} that is a constructor or a * named type that points to such a type. */ public boolean isConstructor() { return false; } /** * Whether this type is a nominal type (a named instance object or * a named enum). */ public boolean isNominalType() { return false; } /** * Whether this type is an Instance object of some constructor. */ public boolean isInstanceType() { return false; } /** * Whether this type is a {@link FunctionType} that is an interface or a named * type that points to such a type. */ public boolean isInterface() { return false; } /** * Whether this type is a {@link FunctionType} that is an ordinary function or * a named type that points to such a type. */ public boolean isOrdinaryFunction() { return false; } /** * This method relies on the fact that for the base {@link JSType}, only one * instance of each sub-type will ever be created in a given registry, so * there is no need to verify members. If the object pointers are not * identical, then the type member must be different. */ @Override public boolean equals(Object jsType) { if (jsType instanceof ProxyObjectType) { return jsType.equals(this); } return this == jsType; } @Override public int hashCode() { return System.identityHashCode(this); } /** * This

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> mean compatible types that do not lead * to step 22 of the definition of the Abstract Equality Comparison * Algorithm (11.9.3, page 55&ndash;56) of the ECMA-262 specification.<p> */ public final boolean canTestForEqualityWith(JSType that) { return this.testForEquality(that).equals(UNKNOWN); } /** * Compares {@code this} and {@code that}. * @return <ul> * <li>{@link TernaryValue#TRUE} if the comparison of values of * {@code this} type and {@code that} always succeed (such as * {@code undefined} compared to {@code null})</li> * <li>{@link TernaryValue#FALSE} if the comparison of values of * {@code this} type and {@code that} always fails (such as * {@code undefined} compared to {@code number})</li> * <li>{@link TernaryValue#UNKNOWN} if the comparison can succeed or * fail depending on the concrete values</li> * </ul> */ public TernaryValue testForEquality(JSType that) { if (that.isAllType() || that.isNoType() || that.isUnknownType()) { return UNKNOWN; } if (that.isEnumElementType()) { return that.testForEquality(this); } if (that instanceof UnionType) { UnionType union = (UnionType) that; TernaryValue result = null; for (JSType t : union.alternates) { TernaryValue test = this.testForEquality(t); if (result == null) { result = test; } else if (!result.equals(test)) { return UNKNOWN; } } } return null; } /** * Tests whether {@code this} and {@code that} are meaningfully * comparable using shallow comparison. By meaningfully, we mean compatible * types that are not rejected by step 1 of the definition of the Strict * Equality Comparison Algorithm (11.9.6, page 56&ndash;57) of the * ECMA-262 specification.<p> */ public final boolean can

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> &#8743; Object} = {@code Number}</li> * </ul> * @return {@code this &#8744; that} */ public JSType getGreatestSubtype(JSType that) { if (that.isRecordType()) { // Record types have their own implementation of getGreatestSubtype. return that.getGreatestSubtype(this); } return getGreatestSubtype(this, that); } /** * A generic implementation meant to be used as a helper for common * getGreatestSubtype implementations. */ static JSType getGreatestSubtype(JSType thisType, JSType thatType) { if (thatType.isEmptyType() || thatType.isAllType()) { // Defer to the implementations of the end lattice elements when // possible. return thatType.getGreatestSubtype(thisType); } else if (thisType.isUnknownType() || thatType.isUnknownType()) { // The greatest subtype with any unknown type is the universal // unknown type, unless the two types are equal. return thisType.equals(thatType) ? thisType : thisType.getNativeType(JSTypeNative.UNKNOWN_TYPE); } else if (thisType.isSubtype(thatType)) { return thisType; } else if (thatType.isSubtype(thisType)) { return thatType; } else if (thisType.isUnionType()) { return ((UnionType) thisType).meet(thatType); } else if (thatType.isUnionType()) { return ((UnionType) thatType).meet(thisType); } else if (thisType.isObject() && thatType.isObject()) { return thisType.getNativeType(JSTypeNative.NO_OBJECT_TYPE); } return thisType.getNativeType(JSTypeNative.NO_TYPE); } /** * Computes the restricted type of this type knowing that the * {@code ToBoolean} predicate has a specific value. For more information * about the {@code ToBoolean} predicate, see * {@link #getPossibleToBooleanOutcomes}. * * @param outcome the value of the {@code ToBoolean} predicate * * @return the restricted type, or the Any Type if the underlying

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> union type's constituents are a subtype of U. Formally<br> * {@code (T<sub>1</sub>, &hellip;, T<sub>n</sub>) &lt;: U} if and only * {@code T<sub>k</sub> &lt;: U} for all {@code k &isin; 1..n}.</li> * <li>(union-r) &mdash; A type U is a subtype of a union type if it is a * subtype of one of the union type's constituents. Formally<br> * {@code U &lt;: (T<sub>1</sub>, &hellip;, T<sub>n</sub>)} if and only * if {@code U &lt;: T<sub>k</sub>} for some index {@code k}.</li> * <li>(objects) &mdash; an Object {@code O<sub>1</sub>} is a subtype * of an object {@code O<sub>2</sub>} if it has more properties * than {@code O<sub>2</sub>} and all common properties are * pairwise subtypes.</li> * </ul> * * @return {@code this &lt;: that} */ public abstract boolean isSubtype(JSType that); /** * Whether this type is meaningfully different from {@code that} type. * This is a trickier check than pure equality, because it has to properly * handle unknown types. * * @see <a href="http://www.youtube.com/watch?v=_RpSv3HjpEw">Unknown * unknowns</a> */ public boolean differsFrom(JSType that) { // if there are no unknowns, just use normal equality. if (!this.isUnknownType() && !that.isUnknownType()) { return !this.equals(that); } // otherwise, they're different iff one is unknown and the other is not. return this.isUnknownType() ^ that.isUnknownType(); } /** * A generic implementation meant to be used as a helper for common subtyping * cases. */ static boolean isSubtype(JSType thisType, JSType thatType) { // unknown if

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> (thatType.isUnknownType()) { return true; } // equality if (thisType.equals(thatType)) { return true; } // all type if (thatType.isAllType()) { return true; } // unions if (thatType instanceof UnionType) { UnionType union = (UnionType)thatType; for (JSType element : union.alternates) { if (thisType.isSubtype(element)) { return true; } } } // named types if (thatType instanceof NamedType) { return thisType.isSubtype(((NamedType)thatType).referencedType); } return false; } /** * Visit this type with the given visitor. * @see com.google.javascript.rhino.jstype.Visitor * @return the value returned by the visitor */ public abstract <T> T visit(Visitor<T> visitor); /** * Resolve this type in the given scope. * * The returned value must be equal to {@code this}, as defined by * {@link Object#equals}. It may or may not be the same object. This method * may modify the internal state of {@code this}, as long as it does * so in a way that preserves Object equality. * * For efficiency, we should only resolve a type once per compilation job. * For incremental compilations, one compilation job may need the * artifacts from a previous generation, so we will eventually need * a generational flag instead of a boolean one. */ public final JSType resolve(ErrorReporter t, StaticScope<JSType> scope) { if (resolved) { // TODO(nicksantos): Check to see if resolve() looped back on itself. // Preconditions.checkNotNull(resolveResult); if (resolveResult == null) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return resolveResult; } resolved = true; resolveResult = resolveInternal(t, scope); return resolveResult; } /** * @see #resolve */ abstract JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); void setResolvedTypeInternal(JSType type) { resolveResult = type

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>Param = null; } } // Right now, the parser's type system doesn't have a good way // to model optional arguments. // // Suppose we have // function f(number, number) {} // function g(number) {} // If the second arg of f is optional, then f is a subtype of g, // but g is not a subtype of f. // If the second arg of f is required, then g is a subtype of f, // but f is not a subtype of g. // // Until we model optional params, let's just punt on this. // If one type has more arguments than the other, we won't check them. // // NOTE(nicksantos): This is described in Draft 2 of the ES4 spec, // Section 3.4.6: Subtyping Function Types. It seems really // strange but I haven't thought a lot about the implementation. } return true; } @Override public boolean equals(Object object) { // Please keep this method in sync with the hashCode() method below. if (!(object instanceof ArrowType)) { return false; } ArrowType that = (ArrowType) object; // if both return types are specified, then they should be equal if (returnType == null) { if (that.returnType != null) { return false; } } else { if (that.returnType == null) { return false; } if (!returnType.equals(that.returnType)) { return false; } } // if both types include parameters, the lists should be the same if (parameters == null) { return that.parameters == null; } else if (that.parameters == null) { return false; } Node thisParam = parameters.getFirstChild(); Node otherParam = that.parameters.getFirstChild(); while (thisParam != null && otherParam != null) { JSType thisParamType = thisParam.getJSType(); JSType otherParamType = otherParam.getJSType(); if (thisParamType != null) { // Both parameter lists give a type for this param, it should be equal if (otherParamType != null && !thisParamType.equals(otherParamType)) {

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> protected JSType createOptionalType(JSType type) { return registry.createOptionalType(type); } /** * Asserts that a Node representing a type expression resolves to the * correct {@code JSType}. */ protected void assertTypeEquals(JSType expected, Node actual) { assertTypeEquals(expected, new JSTypeExpression(actual, "", registry)); } /** * Asserts that a a type expression resolves to the correct {@code JSType}. */ protected void assertTypeEquals(JSType expected, JSTypeExpression actual) { assertEquals(expected, resolve(actual)); } /** * Resolves a type expression, expecting the given warnings. */ protected JSType resolve(JSTypeExpression n, String... warnings) { errorReporter.setWarnings(warnings); return n.evaluate(null); } /** * A definition of all extern types. This should be kept in sync with * javascript/externs/es3.js. This is used to check that the builtin types * declared in {@link JSTypeRegistry} have the same type as that in the * externs. It can also be used for any tests that want to use builtin types * in their externs. */ public static final String ALL_NATIVE_EXTERN_TYPES = "/**\n" + " * @constructor\n" + " * @param {*} opt_value\n" + " */\n" + "function Object(opt_value) {}\n" + "\n" + "/**\n" + " * @constructor\n" + " * @extends {Object}\n" + " * @param {*} var_args\n" + " */\n" + "\n" + "function Function(var_args) {}\n" + "/**\n" + " * @constructor\n" + " * @extends {Object}\n" + " * @param {*} var_args\n" + " * @return {!Array}\n" + " */\n" + "function Array(var_args) {}\n" + "\n" + "/**\n" + " * @constructor\n" + " * @param {*} opt_value\n"

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> < factoryList.size(); i++) { if (factoryList.get(i).getName().equals(passName)) { factoryList.add(i, factory); return; } } throw new IllegalArgumentException( "No factory named '" + passName + "' in the factory list"); } /** * Find the first pass provider that does not have a delegate. */ final PassConfig getBasePassConfig() { PassConfig current = this; while (current instanceof PassConfigDelegate) { current = ((PassConfigDelegate) current).delegate; } return current; } /** * Get intermediate state for a running pass config, so it can * be paused and started again later. */ abstract State getIntermediateState(); /** * Set the intermediate state for a pass config, to restart * a compilation process that had been previously paused. */ abstract void setIntermediateState(State state); /** * An implementation of PassConfig that just proxies all its method calls * into an inner class. */ static class PassConfigDelegate extends PassConfig { private final PassConfig delegate; PassConfigDelegate(PassConfig delegate) { super(delegate.options); this.delegate = delegate; } @Override protected List<PassFactory> getChecks() { return delegate.getChecks(); } @Override protected List<PassFactory> getOptimizations() { return delegate.getOptimizations(); } @Override ScopeCreator getScopeCreator() { return delegate.getScopeCreator(); } @Override Scope getTopScope() { return delegate.getTopScope(); } @Override State getIntermediateState() { return delegate.getIntermediateState(); } @Override void setIntermediateState(State state) { delegate.setIntermediateState(state); } } /** * Intermediate state for a running pass configuration. */ static class State implements Serializable { private static final long serialVersionUID = 1L; final Map<String, Integer> cssNames; final Set<String> exportedNames; final CrossModuleMethodMotion.IdGenerator crossModuleIdGenerator; final VariableMap variableMap; final VariableMap propertyMap; final VariableMap anonymousFunctionNameMap; final FunctionNames functionNames; State(Map<String, Integer> cssNames,

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>.kind = Kind.INTERFACE; this.typeOfThis = new InstanceObjectType(registry, this); } @Override public boolean isInstanceType() { // The universal constructor is its own instance, bizarrely. return equals(registry.getNativeType(U2U_CONSTRUCTOR_TYPE)); } @Override public boolean isConstructor() { return kind == Kind.CONSTRUCTOR; } @Override public boolean isInterface() { return kind == Kind.INTERFACE; } @Override public boolean isOrdinaryFunction() { return kind == Kind.ORDINARY; } @Override public boolean isFunctionType() { return true; } @Override public boolean canBeCalled() { return true; } public Iterable<Node> getParameters() { Node n = getParametersNode(); if (n != null) { return n.children(); } else { return Collections.emptySet(); } } /** Gets an LP node that contains all params. May be null. */ public Node getParametersNode() { return call == null ? null : call.parameters; } /** Gets the minimum number of arguments that this function requires. */ public int getMinArguments() { // NOTE(nicksantos): There are some native functions that have optional // parameters before required parameters. This algorithm finds the position // of the last required parameter. int i = 0; int min = 0; for (Node n : getParameters()) { i++; if (!n.isOptionalArg() && !n.isVarArgs()) { min = i; } } return min; } /** * Gets the maximum number of arguments that this function requires, * or Integer.MAX_VALUE if this is a variable argument function. */ public int getMaxArguments() { Node params = getParametersNode(); if (params != null) { Node lastParam = params.getLastChild(); if (lastParam == null || !lastParam.isVarArgs()) { return params.getChildCount(); } } return Integer.MAX_VALUE; } public JSType getReturnType() { return call == null ? null : call.returnType; } /** * Gets the {@code prototype}

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> implemented directly by a class or its superclass. */ public Iterable<ObjectType> getImplementedInterfaces() { FunctionType superCtor = isConstructor() ? getSuperClassConstructor() : null; if (superCtor == null) { return implementedInterfaces; } else { return Iterables.concat( implementedInterfaces, superCtor.getImplementedInterfaces()); } } public void setImplementedInterfaces(List<ObjectType> implementedInterfaces) { // Records this type for each implemented interface. for (ObjectType type : implementedInterfaces) { registry.registerTypeImplementingInterface(this, type); } this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces); } @Override public boolean hasProperty(String name) { return super.hasProperty(name) || "prototype".equals(name); } @Override public boolean hasOwnProperty(String name) { return super.hasOwnProperty(name) || "prototype".equals(name); } @Override public JSType getPropertyType(String name) { if ("prototype".equals(name)) { return getPrototype(); } else { if (!hasOwnProperty(name)) { if ("call".equals(name)) { // Define the "call" function lazily. Node params = getParametersNode(); if (params == null) { // If there's no params array, don't do any type-checking // in this CALL function. defineDeclaredProperty(name, new FunctionType(registry, null, null, null, getReturnType()), false); } else { params = params.cloneTree(); Node thisTypeNode = Node.newString(Token.NAME, "thisType"); thisTypeNode.setJSType( registry.createOptionalNullableType(getTypeOfThis())); params.addChildToFront(thisTypeNode); thisTypeNode.setOptionalArg(true); defineDeclaredProperty(name, new FunctionType(registry, null, null, params, getReturnType()), false); } } else if ("apply".equals(name)) { // Define the "apply" function lazily. FunctionParamBuilder builder = new FunctionParamBuilder(registry); // Ecma-262 says that apply's second argument must be an Array // or an arguments object. We don't model the arguments object

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>, // so let's just be forgiving for now. // TODO(nicksantos): Model the Arguments object. builder.addOptionalParams( registry.createNullableType(getTypeOfThis()), registry.createNullableType( registry.getNativeType(JSTypeNative.OBJECT_TYPE))); defineDeclaredProperty(name, new FunctionType(registry, null, null, builder.build(), getReturnType()), false); } } return super.getPropertyType(name); } } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { if ("prototype".equals(name)) { ObjectType objType = type.toObjectType(); if (objType != null) { if (objType.equals(prototype)) { return true; } return setPrototype( new FunctionPrototypeType( registry, this, objType, isNativeObjectType())); } else { return false; } } return super.defineProperty(name, type, inferred, inExterns); } @Override public boolean isPropertyTypeInferred(String property) { return "prototype".equals(property) || super.isPropertyTypeInferred(property); } @Override public JSType getLeastSupertype(JSType that) { // NOTE(nicksantos): When we remove the unknown type, the function types // form a lattice with the universal constructor at the top of the lattice, // and the NoObject type at the bottom of the lattice. // // When we introduce the unknown type, it's much more difficult to make // heads or tails of the partial ordering of types, because there's no // clear hierarchy between the different components (parameter types and // return types) in the ArrowType. // // Rather than make the situation more complicated by introducing new // types (like unions of functions), we just fallback on the simpler // approach of using the universal constructor and the AnyObject as // the supremum and infinum of all function types. if (isFunctionType() && that.isFunctionType()) { if (equals(that)) { return this; } JSType functionInstance = registry.getNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS>); if (functionInstance.equals(that)) { return that; } else if (functionInstance.equals(this)) { return this; } return registry.getNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE); } return super.getLeastSupertype(that); } @Override public JSType getGreatestSubtype(JSType that) { if (isFunctionType() && that.isFunctionType()) { if (equals(that)) { return this; } JSType functionInstance = registry.getNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE); if (functionInstance.equals(that)) { return this; } else if (functionInstance.equals(this)) { return that; } return registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE); } return super.getGreatestSubtype(that); } /** * Given a constructor or an interface type, get its superclass constructor * or {@code null} if none exists. */ public FunctionType getSuperClassConstructor() { Preconditions.checkArgument(isConstructor() || isInterface()); ObjectType maybeSuperInstanceType = getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return null; } return maybeSuperInstanceType.getConstructor(); } /** * Given a constructor or an interface type, find out whether the unknown * type is a supertype of the current type. */ public boolean hasUnknownSupertype() { Preconditions.checkArgument(isConstructor() || isInterface()); Preconditions.checkArgument(!this.isUnknownType()); // Potential infinite loop if our type system messes up or someone defines // a bad type. Otherwise the loop should always end. FunctionType ctor = this; while (true) { ObjectType maybeSuperInstanceType = ctor.getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return false; } if (maybeSuperInstanceType.isUnknownType()) { return true; } ctor = maybeSuperInstanceType.getConstructor(); if (ctor == null) { return false; } Preconditions.checkState(ctor.isConstructor() || ctor.isInterface()); } } /**

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> * Given a constructor or an interface type and a property, finds the * top-most superclass that has the property defined (including this * constructor). */ public JSType getTopMostDefiningType(String propertyName) { Preconditions.checkState(isConstructor() || isInterface()); Preconditions.checkArgument(getPrototype().hasProperty(propertyName)); FunctionType ctor = this; JSType topInstanceType; do { topInstanceType = ctor.getInstanceType(); ctor = ctor.getSuperClassConstructor(); } while (ctor != null && ctor.getPrototype().hasProperty(propertyName)); return topInstanceType; } /** * Two function types are equal if their signatures match. Since they don't * have signatures, two interfaces are equal if their names match. */ @Override public boolean equals(Object otherType) { if (!(otherType instanceof FunctionType)) { return false; } FunctionType that = (FunctionType) otherType; if (!that.isFunctionType()) { return false; } if (this.isConstructor()) { if (that.isConstructor()) { return this == that; } return false; } if (this.isInterface()) { if (that.isInterface()) { return this.getReferenceName().equals(that.getReferenceName()); } return false; } if (that.isInterface()) { return false; } return this.typeOfThis.equals(that.typeOfThis) && this.call.equals(that.call); } @Override public int hashCode() { return isInterface() ? getReferenceName().hashCode() : call.hashCode(); } public boolean hasEqualCallType(FunctionType otherType) { return this.call.equals(otherType.call); } /** * Informally, a function is represented by * {@code function (params): returnType} where the {@code params} is a comma * separated list of types, the first one being a special * {@code this:T} if the function expects a known type for {@code this}. */ @Override public String toString() { if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) { return "Function"; } StringBuilder b =

Closure, 136

<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
} else {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (local) {
<CHANGEE>
<CHANGES>
String newName =
MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
if (!newName.equals(name)) {
n.setString(newName);
}
}
<CHANGEE>
<FILEE>
<FILEB> NodeTraversal.traverseRoots( compiler, externsAndJs, getActingCallback()); } /** * Subclasses should return a callback that does the actual work they * want to perform given the computed list of method signatures */ abstract Callback getActingCallback(); /** * Subclasses should return a SignatureStore for storing discovered * signatures. */ abstract SignatureStore getSignatureStore(); /** * Adds a node that may represent a function signature (if it's a function * itself or the name of a function). */ private void addPossibleSignature(String name, Node node, NodeTraversal t) { <CHANGES> boolean signatureAdded = false; <CHANGEE> if (node.getType() == Token.FUNCTION) { // The node we're looking at is a function, so we can add it directly addSignature(name, node, t.getSourceName()); <CHANGES> signatureAdded = true; } else if (node.getType() == Token.NAME) { String functionName = node.getString(); Scope.Var v = t.getScope().getVar(functionName); if (v == null) { if (compiler.isIdeMode()) { return; } else { throw new IllegalStateException( "VarCheck should have caught this undefined function"); } } Node function = v.getInitialValue(); if (function != null && function.getType() == Token.FUNCTION) { addSignature(name, function, v.getInputName()); signatureAdded = true; } } if (!signatureAdded) { <CHANGEE> nonMethodProperties.add(name); } } private void addSignature(String name, Node function, String fnSourceName) { if (externMethodsWithoutSignatures.contains(name)) { return; } getSignatureStore().addSignature(name, function, fnSourceName); methodDefinitions.put(name, function); } /** * Gathers methods from the externs file. Methods that are listed there but <FILEE> <FILEB> } // Is this local or Global? Scope.Var var = t.getScope().getVar(name); boolean local = (var != null) && var.isLocal(); // Are we renaming global variables? if (!local && localRenamingOnly) { reservedNames.add(<SCANS> new StringBuilder(32); b.append("function ("); int paramNum = (call == null || call.parameters == null) ? 0 : call.parameters.getChildCount(); boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType(); if (hasKnownTypeOfThis) { b.append("this:"); b.append(typeOfThis.toString()); } if (paramNum > 0) { if (hasKnownTypeOfThis) { b.append(", "); } Node p = call.parameters.getFirstChild(); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); while (p != null) { b.append(", "); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); } } b.append(")"); if (call != null && call.returnType != null) { b.append(": "); b.append(call.returnType); } return b.toString(); } /** Gets the string representation of a var args param. */ private void appendVarArgsString(StringBuilder builder, JSType paramType) { if (paramType.isUnionType()) { // Remove the optionalness from the var arg. paramType = ((UnionType) paramType).getRestrictedUnion( registry.getNativeType(JSTypeNative.VOID_TYPE)); } builder.append("...[").append(paramType.toString()).append("]"); } /** * A function is a subtype of another if their call methods are related via * subtyping and {@code this} is a subtype of {@code that} with regard to * the prototype chain. */ @Override public boolean isSubtype(JSType that) { if (this.equals(that)) { return true; } if (that.isFunctionType()) { if (((FunctionType) that).isInterface()) { // Any function can be assigned to an interface function. return true; } if (this